介绍
在 flutter web
中, 使用 dart:js_interop
与 JavaScript
应用程序和库以及浏览器API进行通信,Web
开发人员可以在 Dart
代码中使用外部 JS
库,而无需在 Dart
中重写任何内容。
使用
Dart
官方推荐使用 package:web
来替代 dart:html
、dart:indexed_db
、dart:svg
、dart:web_audio
、dart:web_gl
库。使用dart:js_interop
和dart:js_interop_unsafe
替代package:js
、dart:js
、dart:js_util
。
package:web
使用 package:web
需升级 dart sdk
到 3.4.0
安装 package:web
,在 pubspec.yaml
中加入 web: ^1.0.0
,然后执行 flutter pub get
dependencies:
web: ^1.0.0
引入 package:web
import 'package:web/web.dart' as web;
void main() {
print('innerHeight: ${web.window.innerHeight}');
}
dart:js_interop
dart:js_interop
是一个内置的库,无需进行安装。
操作函数
假设项目中引入了一个 js
文件,内容如下:
function doSomething() {
console.log('invoke doSomething function')
}
在 dart
中,要怎么调用这个 doSomething
函数呢?
import 'dart:js_interop';
('doSomething')
external void doSomething();
void main() {
doSomething();
}
js-interop 文档 中表示,处于顶级互操作成员(声明在全局作用域下的)必须使用@JS()
注释声明。
@JS('doSomething')
表示要与 javascript
全局作用域下的 doSomething
互操作,我们知道这个 doSomething
是一个函数,所以它的类型定义为 external void doSomething();
。external
表示外部的,是一个固定的关键字,然后接上函数的返回值类型
,再接上函数名。即可完成一个函数的定义。后面就可以直接使用 doSometing()
来调用该函数。
接下来,来定义一个具有参数和返回值类型的函数:
function doSomething2(num) {
return num;
}
import 'dart:js_interop';
('doSomething2')
external JSNumber doSomething2(JSNumber num);
void main() {
print(doSomething2(100.toJS)); // 100
}
这个例子中,可以看到 100
后面加了 .toJS
,因为 js类型
与 dart类型
基本是不互通的,所以需要通过 toJS
来转换成 js类型
。
操作普通对象
假设引入的 script
文件为:
var obj = {
name: 'Tom',
age: 12,
}
那么 dart
中表示为:
第一种定义方式:
('obj')
external JSObject obj;
当我们调用 obj.age
时,会提示 The setter 'age' isn't defined for the type 'JSObject'. Try importing the library that defines 'age', correcting the name to the name of an existing setter, or defining a setter or field named 'age'.
需要为 obj
定义 age
字段。
为了解决报错,使用第二种定义方式:
import 'dart:js_interop';
import 'package:web/web.dart' as web;
extension type objType._(JSObject _) implements JSObject {
external JSString name;
external JSNumber age;
}
('obj')
external objType obj;
web.console.log(obj);
web.console.log(obj.age);
这里给 obj
定义了类型 objType
。
操作数组
var arr = [1, 2, 3];
extension type Array._(JSArray<JSAny> _) implements JSArray<JSAny> {
external JSAny operator [](int index);
external void operator []=(int index, JSAny value);
external JSNumber get length;
external JSAny push(JSAny value);
}
('arr')
external Array arr;
web.console.log(arr); // [1, 2, 3]
web.console.log(arr[0]); // 1
arr[0] = 100.toJS;
web.console.log(arr[0]); // 100
web.console.log(arr.length); // 3
arr.push(123.toJS);
web.console.log(arr); // [100, 2, 3, 123]
操作类
class Person {
constructor(name, age) {
this._name = name;
this._age = age;
}
get name() {
return this._name;
}
set name(name) {
this._name = name;
}
get age() {
return this._age;
}
set age(age) {
this._age = age;
}
static eat() {
console.log("eat");
}
}
globalThis.Person = Person; // 注意这一行
extension type Person._(JSObject _) implements JSObject {
external Person(JSString name, JSNumber age);
external JSNumber age;
external JSString name;
external static void eat();
}
Person p = Person('Tom'.toJS, 12.toJS);
web.console.log(p); // Person {_name: 'Tom', _age: 12 }
web.console.log(p.name); // Tom
p.name = 'Tom111'.toJS;
web.console.log(p.name); // Tom111
Person.eat(); // eat