是否可以在 Dart 中懒惰地使用 JS 库?
Posted
技术标签:
【中文标题】是否可以在 Dart 中懒惰地使用 JS 库?【英文标题】:is it possible to lazily use JS libs with Dart? 【发布时间】:2019-08-02 10:20:59 【问题描述】:我正在使用 chartjs(带有 dart 接口 https://pub.dartlang.org/packages/chartjs)并试图通过将 <script src="chartjs.js"></script>
注入头部并等待它的加载事件然后使用 lib 来推迟它。
我收到此异常:无法读取未定义的属性“图表”。
当脚本在 dart 之前的 html 头部内时,不会发生这种情况。
那么,是否可以在 Dart 加载后加载 JS 库?
【问题讨论】:
我有在初始化角度组件期间加载 js-library 的经验。 github.com/alexd1971/angular_grecaptcha/blob/master/lib/src/… 在 ngOnInit 脚本标签中创建并添加到 DOM。在 ngAfterViewInit 中等待脚本被加载并初始化组件。但不幸的是,这并不总是有效。例如这里:github.com/alexd1971/angular_flatpickr。我还没找到原因。 听起来像是等待加载完成的问题。我不久前使用过这种方法,它对我有用(虽然不是 Chartjs) 我尝试在 main.dart 上加载脚本以确保它已加载,但仍然没有工作 问题是dart加载后某些JS文件无法添加到dom中。刚刚通过在 main.dart.js 脚本后简单添加<script src=chartjs></script>
对其进行了测试,它抛出了这个错误:Error: Mismatched anonymous define() module: function()var define,module,exports;
【参考方案1】:
这是 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];
【讨论】:
【参考方案2】:找到了更好的方法!
让我们在 dart 加载后删除 define
变量,然后任何第三方库在添加异步时都可以工作:D
将此添加到您的 main():
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>
【讨论】:
【参考方案3】:你可以试试deferred as
语法:
import 'package:chartjs/chartjs.dart' deferred as chartjs;
void main()
chartjs.loadLibrary().then(() ... );
【讨论】:
但这会使界面延迟,而不是实际的 js 脚本,对吧?以上是关于是否可以在 Dart 中懒惰地使用 JS 库?的主要内容,如果未能解决你的问题,请参考以下文章
itertools.product 是不是懒惰地评估它的论点?