本文由 简悦SimpRead 转码,原文地址 codeburst.io
如果你把Dart和......,你是否有过这样的恐惧:把你最喜欢的JS库丢在后面?
如果你将Dart纳入你的开发堆栈,你是否经历过抛弃你最喜欢的JS库的恐惧?不要再害怕了,因为Dart团队提供了一种方法,可以将你最喜欢的JavaScript库纳入其中!这个解决方案以Dart的形式出现。
这个解决方案是以js包的形式出现的,它提供了一个代理来调用JavaScript API方法。在这篇文章中,我们将探讨一些使用window对象的例子,以及一个使用jQuery的真实世界的例子。
下面是包含解决方案的源代码。
前提条件
在我们开始之前,让我们使用stagehand来为我们的web项目提供支架。
mkdir new_project && cd new_project
stagehand web-simple
在pubspec.yaml的依赖项下添加以下内容。
dependencies:
js: ^0.6.0
然后运行pub get。同时确保你已经安装了webdev(pub global activate webdev)
现在我们准备好进入实例了!
window对象的例子
安装js包可以暴露@JS()注解,作为访问window主机对象上的JavaScript API的一种手段。
下面是一个在web/main.dart中使用的片段,用于调用window.console.log()。
@JS() // sets the context, in this case being `window`
library main; // required library declaration
import 'package:js/js.dart'; // Pull in our dependency
@JS('console.log') // annotates `log` function to call `console.log`
external void log(dynamic str);
void main() {
log('Hello world!'); // invokes console.log() in JavaScript land
}
运行webdev serve并访问localhost网址以查看输出。要看到更新,只需保存文件并重新加载页面。
注释的文件必须以一个库声明开始,该声明也有@JS()注释,我们在第1-2行看到。由于第一个注解没有任何参数,它为其他注解设定了相对于window全局对象的上下文。所以到达这一行@JS('console.log')详细说明了从window到console属性的遍历,该属性有log方法。
下面是另一个例子,将上下文设置为window.console。
@JS('console') // Our `console` namespace
library main; // library name can be whatever you want
import 'package:js/js.dart';
@JS('log') // Setting the proxy to the `console.log` method
external void log(dynamic str);
void main() {
log('Hello world!');
}
由于文件是以console命名空间开始的,所以log方法的下一个注释排除了console前缀。log方法的external关键字是用来标记这个方法在Dart之外的,否则就需要一个函数体。此外,由于我们的函数与console上的方法名称相同,我们可以完全删除上面的注释。
// @JS('log') // remove
external void log(dynamic str);
请注意:如果你只需要访问window上的内置属性,你不需要这个互操作包。使用Dart的 dart:html库来完成这个任务。上面的片段只是为了说明问题,因此在使用外部库时,js包就会发挥作用。
使用jQuery的现实世界的例子
为了使用jQuery,让我们在web/index.html中,在请求main.dart.js的脚本标签前导入它。
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
现在,创建一个名为web/jquery.dart的文件,包含下面的片段。
@JS()
library jquery;
import 'package:js/js.dart';
// new jQuery invokes JavaScript `new jQuery()`
@JS()
class jQuery {
external factory jQuery(String selector);
external int get length; // we get this from jQuery instance
}
让我们重构main.dart来测试这个。
import './jquery.dart';
void main() {
print(jQuery('#output')); // [object Object]
print(jQuery('#output').length); // 1
}
让我们通过使用css()和animate()方法做一些更有趣的事情。
@JS()
class jQuery {
external factory jQuery(String selector);
external int get length;
external jQuery css(Map options);
external jQuery animate(Map options);
}
调用这两个方法将返回jQuery实例,就像基于JS的API一样。
现在,这不会像预期的那样工作,因为options参数是期望一个Map类型。我们不能传递一个Dart的Map对象,因为它们在JavaScript中是 "不透明的"。换句话说,你会得到一个不包含你所期望的内容的对象。
为了使其正常工作,我们需要定义一个工厂构造函数,其中包含我们需要的键。
@JS()
@anonymous // needed along with factory constructor
class CssOptions {
external factory CssOptions({ backgroundColor, height, position, width });
external String get backgroundColor;
external String get position;
external num get height;
external num get width;
}
并修改css()外部方法声明如下。
external jQuery css(CssOptions options);
让我们对animate方法做同样的修改。
@JS()
@anonymous
class AnimateOptions {
external factory AnimateOptions({ left, top });
external dynamic get left;
external dynamic get top;
}
并修改animate()外部方法声明如下。
external jQuery animate(AnimateOptions options);
现在我们可以在web/main.dart中调用我们的方法,如下所示。
import './jquery.dart';
void main() {
jQuery('#output')
.css(CssOptions(
backgroundColor: 'green',
height: 100,
position: 'relative',
width: 100))
.animate(AnimateOptions(left: 100, top: 100));
}
并期待下面的结果。
知道你可以保持作为Dart开发者的生产力,同时保持对JavaScript库生态系统的访问,会使事情变得更好,因为任何新冒出来的库仍然在你的掌握之中。
这个解决方案适用于任何在 "window "对象下有命名空间的JavaScript库,这涵盖了_99%的情况。
像往常一样,我希望这篇文章很有见地,你今天学到了一些新东西。这里是包含完整解决方案的要旨。