能否在Dart中懒惰地使用JS库?

4
我正在使用chartjs(使用dart接口https://pub.dartlang.org/packages/chartjs),并尝试通过将<script src="chartjs.js"></script>注入到head部分并等待其加载事件,使其延迟使用该库。
我遇到了这个异常:无法读取未定义的属性'Chart'。

当脚本在html头部之前的位置时,就不会发生这种情况。

那么,在Dart加载后是否可以加载JS库呢?


1
我有经验在Angular组件初始化期间加载js库。https://github.com/alexd1971/angular_grecaptcha/blob/master/lib/src/recaptcha.dart 在ngOnInit中创建脚本标签并添加到DOM中。在ngAfterViewInit中等待脚本加载并初始化组件。但是这不总是有效的。例如在这里:https://github.com/alexd1971/angular_flatpickr。我还没有找出原因。 - Aleksey Danilevskiy
听起来像是等待加载完成的问题。我以前用过这种方法,对我有用(不过没有用在Chartjs上)。 - Günter Zöchbauer
我尝试将脚本加载到 main.dart 上以确保它已加载,但仍然无法工作。 - Jonathan
问题在于,在加载Dart之后,某些JS文件无法添加到DOM中。我刚刚测试了一下,只需在main.dart.js脚本后面简单地添加<script src=chartjs></script>,就会抛出以下错误:Error: Mismatched anonymous define() module: function(){var define,module,exports; - Jonathan
3个回答

3

这是DDC中的一个问题。它将require.js添加到HTML中并与其他库发生冲突。
https://github.com/dart-lang/sdk/issues/33979

我找到的解决方法是手动从您想要使用的第三方库中删除使用requirejs的头部节。

例如,以chartjs为例:https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.js

您需要删除以下两行:

typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(function() { try { return require('moment'); } catch(e) { } }()) :
typeof define === 'function' && define.amd ? define(['require'], function(require) { return factory(function() { try { return require('moment'); } catch(e) { } }()); }) :

然后文件可以被惰性地添加到DOM中,而不会发生冲突。

这是我的用于惰性获取脚本的代码:

class ClientUtils {
    static final _scriptFetched = <String, Future<bool>>{};

    static ScriptElement _scr(String url) => new ScriptElement()
      ..async = true
      ..type = 'text/javascript'
      ..src = url;

    static Future<bool> fetchScript(String url,
            {String contextCheck}) async {
        bool shouldCheck = contextCheck?.isNotEmpty == true;

        hasContext() => js.context.hasProperty(contextCheck) &&
                    js.context[contextCheck] != null;

        if (shouldCheck && hasContext())
            return true;

        if (!_scriptFetched.containsKey(url)) {
            Completer<bool> c = new Completer<bool>();

            if (!shouldCheck) {
                ScriptElement s = _scr(url)
                    ..onLoad.forEach((Event e) {
                        c.complete(true);
                    });

                document.body.children.add(s);
            } else {
                Timer.periodic(Duration(milliseconds: 300), (t) {
                    if (hasContext()) {
                        t.cancel();
                    }
                    c.complete(true);
                });

                document.body.children.add(_scr(url));
            }

            _scriptFetched[url] = c.future;
        }
        return _scriptFetched[url];
    }
}


3

发现更好的方法!

让我们在Dart加载后删除define变量,然后任何第三方库在异步添加时都可以工作:D

将以下内容添加到您的主函数中:

import 'dart:js';

void main() {
  context.callMethod('fixRequireJs');
}

在你的index.html中:
    <script type="text/javascript">
      window.fixRequireJs = function()
      {
        console.log('define is ', typeof define);
        if (typeof define == 'function') {
          console.log('removing define...');
          delete define;
          window.define = null;
        }
      }
    </script>

0
你可以尝试使用deferred as语法:
import 'package:chartjs/chartjs.dart' deferred as chartjs;

void main() {
    chartjs.loadLibrary().then(() { ... });
}

但这只是使接口延迟,而不是实际的JS脚本,对吗? - Jonathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接