我正在寻找与new JsObject.jsify
相反的方法。希望能够将javascript的Object
转换回Dart的Map
。是否有可用的方法?
我知道可以使用JSON将其转换为字符串,但这并不能解决包含函数、Dart对象、Dom元素等内容的Object
的传输问题...是否有更好的方法?
我正在寻找与new JsObject.jsify
相反的方法。希望能够将javascript的Object
转换回Dart的Map
。是否有可用的方法?
我知道可以使用JSON将其转换为字符串,但这并不能解决包含函数、Dart对象、Dom元素等内容的Object
的传输问题...是否有更好的方法?
Map map = JSON.decode(
context['JSON'].callMethod(
'stringify',
[context['map']]
)
);
JsObject
处理成像Map<String, dynamic>
一样的格式:import 'dart:collection' show Maps;
import 'dart:js';
class JsMap implements Map<String,dynamic> {
final JsObject _jsObject;
JsMap.fromJsObject(this._jsObject);
operator [](String key) => _jsObject[key];
void operator []=(String key, value) {
_jsObject[key] = value;
}
remove(String key) {
final value = this[key];
_jsObject.deleteProperty(key);
return value;
}
Iterable<String> get keys => context['Object'].callMethod('keys', [_jsObject]);
// use Maps to implement functions
bool containsValue(value) => Maps.containsValue(this, value);
bool containsKey(String key) => keys.contains(key);
putIfAbsent(String key, ifAbsent()) => Maps.putIfAbsent(this, key, ifAbsent);
void addAll(Map<String, dynamic> other) {
if (other != null) {
other.forEach((k,v) => this[k] = v);
}
}
void clear() => Maps.clear(this);
void forEach(void f(String key, value)) => Maps.forEach(this, f);
Iterable get values => Maps.getValues(this);
int get length => Maps.length(this);
bool get isEmpty => Maps.isEmpty(this);
bool get isNotEmpty => Maps.isNotEmpty(this);
}
_toDartSimpleObject(thing) {
if (thing is js.JsArray) {
List res = new List();
js.JsArray a = thing as js.JsArray;
a.forEach((otherthing) {
res.add(_toDartSimpleObject(otherthing));
});
return res;
} else if (thing is js.JsObject) {
Map res = new Map();
js.JsObject o = thing as js.JsObject;
Iterable<String> k = js.context['Object'].callMethod('keys', [o]);
k.forEach((String k) {
res[k] = _toDartSimpleObject(o[k]);
});
return res;
} else {
return thing;
}
}
将任何JS对象递归转换为Dart映射、列表或标量值:
/// js_interop.dart
import 'dart:js';
/// Converts the specified JavaScript [value] to a Dart instance.
dynamic convertToDart(value) {
// Value types.
if (value == null) return null;
if (value is bool || value is num || value is DateTime || value is String) return value;
// JsArray.
if (value is Iterable) return value.map(convertToDart).toList();
// JsObject.
return new Map.fromIterable(getKeysOfObject(value), value: (key) => convertToDart(value[key]));
}
/// Gets the enumerable properties of the specified JavaScript [object].
List<String> getKeysOfObject(JsObject object) => (context['Object'] as JsFunction).callMethod('keys', [object]);
使用方法:
/// config.js
window.$environment = 'staging';
window.$config = {
name: 'FooBar',
params: {
assets: ['css', 'js'],
forceSsl: true
}
};
/// main.dart
import 'dart:js' as js;
import 'js_interop.dart';
void main() {
var environment = convertToDart(js.context[r'$environment']);
assert(environment is String);
assert(environment == 'staging');
var config = convertToDart(js.context[r'$config']);
assert(config is Map<String, dynamic>);
assert(config.length == 2);
assert(config['name'] is String);
assert(config['name'] == 'FooBar');
assert(config['params'] is Map<String, dynamic>);
assert(config['params'].length == 2);
assert(config['params']['forceSsl'] is bool);
assert(config['params']['forceSsl'] == true);
assert(config['params']['assets'] is List<String>);
assert(config['params']['assets'].length == 2);
assert(config['params']['assets'].first == 'css');
assert(config['params']['assets'].last == 'js');
}
我知道我在重提一个已经过时的话题,但是我为了解决这个问题而苦苦思索,虽然这是谷歌搜索结果中排名最高的,但是里面的答案并没有帮到我。
这里有一个更简单的实现方法,尽管我认为它只适用于Flutter Web。
我包含了mapify(将Json对象转换为dart map)以及它的相反操作(从dart map创建json对象)。
import 'dart:convert' show jsonDecode;
import 'dart:js';
Map? mapify(JsObject? obj) {
if (obj == null) return null;
return jsonDecode(context['JSON'].callMethod('stringify', [obj]));
}
JsObject jsify(object) => JsObject.jsify(object);
以上所有答案对我都没有用。
matanlurey提供了一个看起来更为更新的解决方案,对我实际有效(Dart SDK 1.24.0),在这里:
https://dev59.com/z53ha4cB1Zd3GeqPWZBa#41291503
简而言之,它非常相似,但使用新的package:js
代替dart:js
。