[Dart翻译]如何在你的Dart应用程序中使用JavaScript库

1,140 阅读4分钟

本文由 简悦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')详细说明了从windowconsole属性的遍历,该属性有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));
}

并期待下面的结果。

1.gif

知道你可以保持作为Dart开发者的生产力,同时保持对JavaScript库生态系统的访问,会使事情变得更好,因为任何新冒出来的库仍然在你的掌握之中。

这个解决方案适用于任何在 "window "对象下有命名空间的JavaScript库,这涵盖了_99%的情况。

像往常一样,我希望这篇文章很有见地,你今天学到了一些新东西。这里是包含完整解决方案的要旨

  1. js包在Pub上
  2. Vue.js-Getting started in Dart
  3. Egghead.io上的免费Dart截屏

www.deepl.com 翻译