简体   繁体   English

如何使用 JavaScript 在 IFrameElement 和 Dart 之间进行通信?

[英]How can I communicate between an IFrameElement and Dart using JavaScript?

I'm a noob to Flutter Web.我是 Flutter Web 的菜鸟。 I have a package that I'm trying to create support for in Flutter Web, but it uses a webview for some functions. I have a package that I'm trying to create support for in Flutter Web, but it uses a webview for some functions. Webviews aren't supported in Flutter Web so I'm using a IFrameElement and ui.platformViewRegistry.registerViewFactory() to act like a webview. Flutter Web 不支持 Webview,所以我使用IFrameElementui.platformViewRegistry.registerViewFactory()来充当 Z5A98E2840FD0141780D854E48C608D I'm passing an HTML String to be loaded rather than a file.我正在传递要加载的 HTML 字符串而不是文件。

I need to be able to run JS functions and get data from JS.我需要能够运行 JS 函数并从 JS 获取数据。 I've tried a lot of different things with events and event listeners, also context.callMethod() and none of it has worked so far.我已经用事件和事件监听器尝试了很多不同的东西,还有context.callMethod() ,但到目前为止都没有奏效。 Is there a simple way to accomplish this?有没有一种简单的方法可以做到这一点?

For reference, I am using the Summernote library and I can run something like \$('#summernote').summernote('reset');作为参考,我正在使用 Summernote 库,我可以运行类似\$('#summernote').summernote('reset'); to reset the Summernote editor.重置 Summernote 编辑器。 Sometimes I need to get data from JS so I am running var str = \$('#summernote').summernote('code'); console.log(str);有时我需要从 JS 获取数据,所以我正在运行var str = \$('#summernote').summernote('code'); console.log(str); var str = \$('#summernote').summernote('code'); console.log(str); which gives me the HTML code in the editor.这给了我编辑器中的 HTML 代码。

Thanks in advance!提前致谢!

Code for reference:参考代码:

import 'dart:convert';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:html_editor_enhanced/html_editor.dart';
import 'package:html_editor_enhanced/utils/pick_image.dart';
import 'package:path/path.dart' as p;
import 'package:flutter/material.dart';
import 'dart:html' as html;
import 'dart:js' as js;
import 'dart:ui' as ui;

bool callbacksInitialized = false;
js.JsObject jsDocument;

class HtmlEditorWidgetWeb extends StatelessWidget {
  HtmlEditorWidgetWeb({
    Key key,
    this.value,
    this.height,
    this.useBottomSheet,
    this.imageWidth,
    this.showBottomToolbar,
    this.hint,
    this.callbacks,
    this.toolbar,
    this.darkMode
  }) : super(key: key);

  final String value;
  final double height;
  final bool useBottomSheet;
  final double imageWidth;
  final bool showBottomToolbar;
  final String hint;
  final UniqueKey webViewKey = UniqueKey();
  final Callbacks callbacks;
  final List<Toolbar> toolbar;
  final bool darkMode;
  final String createdViewId = 'html_editor_web';

  @override
  Widget build(BuildContext context) {
    String summernoteToolbar = "[\n";
    for (Toolbar t in toolbar) {
      summernoteToolbar = summernoteToolbar +
          "['${t.getGroupName()}', ${t.getButtons()}],\n";
    }
    summernoteToolbar = summernoteToolbar + "],";
    String darkCSS = "";
    if ((Theme.of(context).brightness == Brightness.dark || darkMode == true) && darkMode != false) {
      darkCSS = "<link href=\"packages/html_editor_enhanced/assets/summernote-lite-dark.css\" rel=\"stylesheet\">";
    }
    String htmlString = """
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <meta name="description" content="Flutter Summernote HTML Editor">
        <meta name="author" content="xrb21">
        <title>Summernote Text Editor HTML</title>
        <script src="main.dart.js" type="application/javascript"></script>
        <script src="app.js" defer></script>
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
        <link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.css" rel="stylesheet">
        <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.js"></script>
        $darkCSS
        <script>
        function test() {
              console.log("Listening");
          }
        </script>
      </head>
      <body>
      <div id="summernote-2"></div>
      <script type="text/javascript">
          \$('#summernote-2').summernote({
            placeholder: "$hint",
            tabsize: 2,
            height: ${height - 125},
            maxHeight: ${height - 125},
            toolbar: $summernoteToolbar
            disableGrammar: false,
            spellCheck: false
          });
          
          document.addEventListener("setFS", function(){
            console.log('fired');
            \$('#summernote-2').summernote("fullscreen.toggle");
            
          });          
      </script>
      <style>
        body {
            display: block;
            margin: 0px;
        }
        .note-editor.note-airframe, .note-editor.note-frame {
            border: 0px solid #a9a9a9;
        }
        .note-frame {
            border-radius: 0px;
        }
      </style>
      </body>
      </html>
    """;
    html.window.onMessage.forEach((element) {
      print('Event Received in callback: ${element.data}');
    });
    // todo use postmessage and concatenation to accomplish callbacks
    final html.IFrameElement iframe = html.IFrameElement()
      ..width = MediaQuery.of(context).size.width.toString() //'800'
      ..height = MediaQuery.of(context).size.height.toString() //'400'
      ..srcdoc = htmlString
      ..style.border = 'none'
      ..onLoad.listen((event) async {
        html.document.on['setFS'].listen((html.Event event) {
          print("HEY! I'M LISTENING!");
        });
html.document.dispatchEvent(html.Event("setFS"));
      });
    ui.platformViewRegistry.registerViewFactory(
        createdViewId, (int viewId) => iframe);
    return Column(
      children: <Widget>[
        Expanded(
          child: Directionality(
            textDirection: TextDirection.ltr,
            child: HtmlElementView(
              viewType: createdViewId,
            )
          )
        ),
      ],
    );
  }
}

A little bit hacky, but here's the solution I use:有点hacky,但这是我使用的解决方案:

Dart -> JS Dart -> JS

In dart:在 dart 中:

html.window.postMessage(//data to send here, "*");

and in the IframeElement HTML <script> :并在 IframeElement HTML <script>中:

window.parent.addEventListener('message', handleMessage, false);
      
function handleMessage(e) {
   var data = e.data;
}

I personally use JSON when sending data to make it easier to send/receive/parse.我个人在发送数据时使用 JSON 以使其更容易发送/接收/解析。 So in Dart that is a Map<String, dynamic> , sent like this:所以在 Dart 中,它是一个Map<String, dynamic> ,发送如下:

final data = Map<String, dynamic>{
   //your data here
}
final jsonEncoder = JsonEncoder();
final json = jsonEncoder.convert(data);
html.window.postMessage(json, "*");

and in JS:在 JS 中:

window.parent.addEventListener('message', handleMessage, false);
      
function handleMessage(e) {
   var data = JSON.parse(e.data);
}

A suggestion would be to create a unique key/string that you can pass in between JS and Dart so you make sure you are intercepting the correct postMessage every time.一个建议是创建一个唯一的键/字符串,您可以在 JS 和 Dart 之间传递它,以便确保每次都拦截正确的postMessage

JS -> Dart JS -> Dart

In the IframeElement HTML <script> :IframeElement HTML <script>中:

window.parent.postMessage(//data to send, "*");

and in Dart:在 Dart 中:

html.window.onMessage.listen((event) {
   var data = event.data;
});

Again, I use JSON to communicate because I think it makes things easier.同样,我使用 JSON 进行通信,因为我认为它使事情变得更容易。 Use JSON.stringify() in JS and json.decode() in Dart.在 JS 中使用JSON.stringify() json.decode()在 Dart 中使用 json.decode()。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM