Flutter在web项目中使用iframe
需要把原来的app项目移植到web上面,在app中使用的是flutter_inappwebview这个库,推荐使用这个库,因为修复了一部分webview_flutter中存在的问题
在web项目中flutter_inappwebview这个库不支持,所以需要自己封装一个web项目中的webview也就是使用iframe
废话少说上代码
import 'dart:html';
import 'dart:js' as js;
import 'dart:ui_web';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:myapp/app/services/screen_adapter.dart';
Widget buildWebViewWidget(String url,
{Function(int id)? onPlatformViewCreated}) {
/// 给js调用的函数
void back(){
Get.back();
}
var platformViewRegistry = PlatformViewRegistry();
//注册
platformViewRegistry.registerViewFactory('iframe-webview', (_) {
DivElement _mainDiv = DivElement()
..style.width = '100%'
..style.height = '100%'
..style.position = 'relative';
IFrameElement _iFameElement = IFrameElement()
..style.height = '100%'
..style.width = '100%'
..src = url
..style.border = 'none';
ScriptElement scriptElement = ScriptElement();
var script = """
// 对话框js
window.confirm = function(message, yesCallback, noCallback){
var message = message;
var choose = function(tag){
return document.querySelector(tag);
}
choose('.dialog-message').innerHtml = message;
choose(".wrap-dialog").className = "wrap-dialog";
choose("#dialog").οnclick= function(e){
if(e.target.className=="dialog-btn"){
choose(".wrap-dialog").className = "wrap-dialog dialog-hide";
yesCallback();
}else if (e.target.className=="dialog-btn dialog-ml50"){
choose(".wrap-dialog").className = "wrap-dialog dialog-hide";
noCallback();
}
};
}
// 返回按钮功能
var drag = document.getElementById("floatBtn");
var gapWidth = ${ScreenAdapter.width(5)}
var itemWidth = ${ScreenAdapter.width(80)}
var itemHeight = ${ScreenAdapter.width(80)}
var clientWidth = document.documentElement.clientWidth
var clientHeight = document.documentElement.clientHeight
var newLeft = 0
var newTop = 0
drag.addEventListener('click',function(e){
//e.stopPropagation();
var r = confirm('确定返回首页吗?', function(){
window.back();
}, function(){})
})
drag.addEventListener('touchstart', function(e){
// e.preventDefault();
//e.stopPropagation();
drag.style.transition = 'none';
})
drag.addEventListener('touchmove', function(e){
// e.preventDefault();
// e.stopPropagation();
if (e.targetTouches.length === 1) {
let touch = e.targetTouches[0]
newLeft = touch.clientX - itemWidth / 2;
newTop = touch.clientY - itemHeight / 2;
if(newLeft < 0){
newLeft = 0
}
if(newLeft > clientWidth - itemWidth - gapWidth){
newLeft > clientWidth - itemWidth - gapWidth
}
if(newTop < 0){
newTop=0;
}
if(newTop > clientHeight - itemHeight - gapWidth){
newTop = clientHeight - itemHeight - gapWidth
}
drag.style.left = newLeft + 'px'
drag.style.top = newTop + 'px'
}
})
drag.addEventListener('touchend', function (e) {
// e.preventDefault()
//e.stopPropagation();
drag.style.transition = 'all 0.3s'
if (newLeft > clientWidth / 2) {
newLeft = clientWidth - itemWidth - gapWidth
} else {
newLeft = gapWidth
}
drag.style.left = newLeft + 'px'
})
""";
scriptElement.innerHtml = script;
/// 返回按钮div
DivElement _div = DivElement()
..id = 'floatBtn'
..draggable = true
..style.width = '${ScreenAdapter.width(80)}px'
..style.height = '${ScreenAdapter.width(80)}px'
// ..style.backgroundColor = 'red'
..style.backgroundImage = 'url(assets/assets/images/fanhui.png)'
..style.backgroundSize = 'cover'
..style.position = 'absolute'
..style.left = '${ScreenAdapter.width(5)}px'
..style.top = '0'
..style.transition = 'all 0.3s'
..style.zIndex = '9999';
// 对话框样式
StyleElement _style = StyleElement();
_style.innerHtml = """
html,
body {
margin: 0;
padding: 0;
font-family: "Microsoft YaHei";
}
.wrap-dialog {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
font-size: 16px;
text-align: center;
background-color: rgba(0, 0, 0, .4);
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
}
.dialog {
position: relative;
margin: 10% auto;
width: 300px;
background-color: #FFFFFF;
}
.dialog .dialog-header {
height: 20px;
padding: 10px;
background-color: #22b9ff;
}
.dialog .dialog-body {
height: 30px;
padding: 20px;
}
.dialog .dialog-footer {
padding: 8px;
background-color: #f5f5f5;
}
.dialog-btn {
width: 70px;
padding: 2px;
cursor: pointer;
}
.dialog-hide {
display: none;
}
.dialog-ml50 {
margin-left: 50px;
}
""";
_mainDiv.append(_style);
// 提示信息框dom
DivElement _dialogDiv = DivElement();
_dialogDiv.innerHtml = """
<div class="wrap-dialog dialog-hide" >
<div class="dialog" id="dialog">
<div class="dialog-header">
<span class="dialog-title">提示</span>
</div>
<div class="dialog-body">
<span class="dialog-message">确定要返回首页吗?</span>
</div>
<div class="dialog-footer">
<input type="button" class="dialog-btn" id="dialog-confirm" value="确认" />
<input type="button" class="dialog-btn dialog-ml50" id="dialog-cancel" value="取消" />
</div>
</div>
</div>
""";
_mainDiv.append(scriptElement);
_mainDiv.append(_dialogDiv);
_mainDiv.append(_div);
_mainDiv.append(_iFameElement);
return _mainDiv;
});
/// 注册返回函数
js.context['back'] = back;
return SizedBox(
width: double.infinity,
height: double.infinity,
child: HtmlElementView(
viewType: 'iframe-webview',
onPlatformViewCreated: (int id) {
onPlatformViewCreated?.call(id);
},
),
);
}
使用方法
直接判断是否是web,GetPlatform.isWeb ,如果是则使用上面封装的,不是则调用其他平台的
if(GetPlatform.isWeb)
buildWebViewWidgetPlatform(controller.url,
onPlatformViewCreated: (id) {
controller.isLoading.value = false;
})
参考网址
https://juejin.cn/post/7294638699417042954