当前位置: 首页 > article >正文

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


http://www.kler.cn/news/136008.html

相关文章:

  • html主页框架,前端首页通用架构,layui主页架构框架,首页框架模板
  • 设计原则 | 开放封闭原则
  • LeetCode【92】翻转链表II
  • 将Excel中的数据导入shell脚本
  • 用java编写图书管理系统
  • HDCTF2023 - Reverse方向全WP
  • 在Oracle 11g 数据库上设置透明数据加密(TDE)
  • 【SpringCloud】Eureka基于Ribbon负载均衡的调用链路流程分析
  • BLIP-2:冻结现有视觉模型和大语言模型的预训练模型
  • C#具名参数(Named Parameters)
  • Ubuntu下发送邮件
  • C#编程题分享(1)
  • 【亚马逊云科技产品测评】活动征文|aws云服务器 + 微服务Spring Cloud Nacos 实战
  • 使用Java解决快手滑块验证码
  • unity 打包exe设置分辨率
  • 线上bug-接口速度慢
  • Spring Boot - 自定义注解来记录访问路径以及访问信息,并将记录存储到MySQL
  • 解决 Python requests 库中 SSL 错误转换为 Timeouts 问题
  • 使用 Core Tools 在本地开发 Azure Functions
  • 【图数据库实战】-HugeGraph系列
  • SpringCloud 微服务全栈体系(十四)
  • 【brpc学习案例实践一】rpc服务构造基本流程
  • 彻底解决electron-builder安装问题与npm下载配置问题
  • Docker发布简单springboot项目
  • C++ 删除无头链上所有指定值为x的节点。
  • Redis设计与实现-数据结构(建设进度15%)
  • Re50:读论文 Large Language Models Struggle to Learn Long-Tail Knowledge
  • ubuntu 查看5000端口是否开放
  • 2023 极术通讯-汽车“新四化”路上,需要一片安全山海
  • 享元模式学习