本文持续记录fair界面的不同写法对fair delegate办法调用的处理的源码完成进程。 fair delegate
FairWidget界面解析2种正则匹配办法
在FairWidget 的build办法的界面解析进程 两种办法的写法将会走不同的流程。
- GestureExpression
正则:
RegExp(r'@(.+)', multiLine: false).hasMatch(exp ?? '');
将运用bindFunctionOf办法。
- FunctionExpression
正则:
RegExp(r'%(.+)', multiLine: false).hasMatch(exp ?? '');
将运用runFunctionOf 办法。
GestureExpression办法
这种办法为@(medalsInfoWidget) @开头的这种款式。
写法为:
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Builder(
builder: medalsInfoWidget,
),
),
Widget medalsInfoWidget(context) {
return Container();
}
他转化成json内容为:
{
"className": "Padding",
"na": {
"padding": {
"className": "EdgeInsets.symmetric",
"na": {
"horizontal": 20
}
},
"child": {
"className": "Builder",
"na": {
"builder": "@(medalsInfoWidget)"
}
}
}
},
"medalsInfoWidget": {
"className": "Container"
}
JS文件中这种办法将不会有medalsInfoWidget js函数生成。
运转进程中: 将会匹配到GestureExpression 履行bindFunction逻辑:
dynamic bindFunctionOf(String funcName, ProxyMirror? proxyMirror,
BindingData? bound, Domain? domain,
{String? exp}) {
if (_functions?[funcName] == null) {
if (RegExp(r'.+(.+)', multiLine: false).hasMatch(funcName)) {
var rFuncName = funcName.substring(0, funcName.indexOf('('));
var params = funcName.substring(
funcName.indexOf('(') + 1, funcName.lastIndexOf(')'));
var args = params.split(',').map((e) {
if (RegExp(r'^(index)', multiLine: false).hasMatch(e) &&
domain is IndexDomain?) {
return domain?.index;
} else if (domain != null && domain.match(e)) {
return domain.bindValue(e);
} else {
var r = proxyMirror?.evaluate(null, bound, e, domain: domain);
if (r?.data == null) {
return e;
} else {
return r?.data is ValueNotifier ? r?.data.value : r?.data;
}
}
}).toList();
return ([props]) {
var arguments = [];
if (props != null) {
arguments.add(props);
}
if (args != null) {
arguments.addAll(args);
}
_functions?['runtimeInvokeMethod']?.call(rFuncName, true, arguments);
};
} else {
return ([props]) =>
_functions?['runtimeInvokeMethod']?.call(funcName, false, props);
}
} else {
return _functions?[funcName]; //由于咱们完成了delegate 所以medalsInfoWidget 会履行delegate办法
}
}
对应咱们的署理办法完成为:
Map<String, Function> bindFunction() {
var bindFunction = super.bindFunction();
bindFunction.addAll({
'medalsInfoWidget': _medalsInfoWidget,
});
return bindFunction;
}
Widget _medalsInfoWidget(context) { //这个context 不是从js传递过来的。是从build进程中获取传递的对应层的context
//context
}
整体的运转进程如下:
调用1:
调用2:
调用3:
调用4:
FunctionExpression 办法
这种办法为%(medalsInfoWidget2) %开头的这种款式。
Widget的写法为:
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: medalsInfoWidget2(),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: medalsInfoWidget3(),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: medalsInfoWidget4(),
),
//这种办法可以-避免生成methodMap
medalsInfoWidget2() {}
// 不能写回来值,写回来值不会走delegate和js,生成methodMap走methodMap
Widget medalsInfoWidget3() {
return Container();
}
// 不能写回来值,写回来值不会走delegate和js,生成methodMap走methodMap
Text medalsInfoWidget4() {
return const Text('1234');
}
转化成json为
{
"className": "Padding",
"na": {
"padding": {
"className": "EdgeInsets.symmetric",
"na": {
"horizontal": 20
}
},
"child": "%(medalsInfoWidget2)"//FunctionExpression: runFunctionOf
}
},
{
"className": "Padding",
"na": {
"padding": {
"className": "EdgeInsets.symmetric",
"na": {
"horizontal": 20
}
},
"child": "%(medalsInfoWidget3)"//
}
},
{
"className": "Padding",
"na": {
"padding": {
"className": "EdgeInsets.symmetric",
"na": {
"horizontal": 20
}
},
"child": "%(medalsInfoWidget4)"//
}
},
//build以外的办法生成methodMap状况如下:
"methodMap": {
//不会在methodMap生成内容: medalsInfoWidget2() {} 可是生成了js办法
//%(medalsInfoWidget3)不会走署理,没有生成js办法 。假如是第一种状况"builder":"@(medalsInfoWidget)"能走署理
// 有回来值的: Widget medalsInfoWidget3()
"medalsInfoWidget3": {
"className": "Container"
},
//%(medalsInfoWidget4)不会走署理
// 有回来值的: Text medalsInfoWidget4() {return const Text('1234');}
"medalsInfoWidget4": {
"className": "Text",
"pa": [
"1234"
]
}
}
js办法为:
medalsInfoWidget2: function medalsInfoWidget2() {
const __thiz__ = this;
with(__thiz__) {}
},
medalsInfoWidget4: function medalsInfoWidget4() {
const __thiz__ = this;
with(__thiz__) {
return new Text('1234');
}
},
总结就是build之外的办法,
- 假如回来return目标的类型是Widget,Text,Container是flutter widget类型的就会生成methodMap。%(xx)FunctionExpression这种表达式匹配出来,将会走methodMap映射创建widget。不会调用js和delegate。
- 所以上述完成中,%(medalsInfoWidget2) 函数的完成不回来任何目标,以便运转时调用delegate办法
- 回来值类型是Widget(是回来值类型,不是return的目标的类型)不会生成js办法。其余状况都将会生成js办法
对应咱们的署理办法完成为:
Map<String, Function> bindFunction() {
var bindFunction = super.bindFunction();
bindFunction.addAll({
'medalsInfoWidget2': _medalsInfoWidget2,
});
return bindFunction;
}
Widget _medalsInfoWidget2() {
}
运转进程中: 将会匹配到 FunctionExpression 履行 runFunctionOf 逻辑:
%(medalsInfoWidget2)履行 :
dynamic runFunctionOf(String funcName, ProxyMirror? proxyMirror, BindingData? bound, Domain? domain, {String? exp})
_functions?[funcName]?.call();
runFunctionOf完整完成为:
dynamic runFunctionOf(String funcName, ProxyMirror? proxyMirror,
BindingData? bound, Domain? domain,
{String? exp}) {
if (_functions?[funcName] == null) {
var result;
if (RegExp(r'.+(.+)', multiLine: false).hasMatch(funcName)) {
var rFuncName = funcName.substring(0, funcName.indexOf('('));
var params = funcName.substring(
funcName.indexOf('(') + 1, funcName.lastIndexOf(')'));
var args = params.split(',').map((e) {
if (RegExp(r'^(index)', multiLine: false).hasMatch(e) &&
domain is IndexDomain?) {
return domain?.index;
} else if (domain != null && domain.match(e)) {
return domain.bindValue(e);
} else {
var r = proxyMirror?.evaluate(null, bound, e, domain: domain);
if (r?.data == null) {
return e;
} else {
return r?.data is ValueNotifier ? r?.data.value : r?.data;
}
}
}).toList();
result = _functions?['runtimeInvokeMethodSync']?.call(rFuncName, args);
} else {
result = _functions?['runtimeInvokeMethodSync']?.call(funcName);
}
try {
var value = jsonDecode(result);
return value['result']['result'];
} catch (e) {
throw RuntimeError(errorMsg: result);
}
} else {
return _functions?[funcName]?.call();//所以这儿的delegate的办法也是不能支撑携带参数
}
}
methodMap办法
Function.apply(
fun, [Property.extract(list: pa.data, map: na.data)], null);
关于上面%(medalsInfoWidget4) 为什么没有去调用js函数,也没走delegate,是由于这个办法生成了methodMap:
dart界面写法:
Widget build(BuildContext context) {
....
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: medalsInfoWidget4(),
),
...
}
Text medalsInfoWidget4() {
return const Text('1234');
}
生成的json和js:
{
"className": "Padding",
"na": {
"padding": {
"className": "EdgeInsets.symmetric",
"na": {
"horizontal": 20
}
},
"child": "%(medalsInfoWidget4)"
}
},
"methodMap": {
"medalsInfoWidget4": {
"className": "Text",
"pa": [
"1234"
]
}
},
//下面为js办法。 这儿这个js函数是不会履行的:
medalsInfoWidget4: function medalsInfoWidget4() {
const __thiz__ = this;
with(__thiz__) {
return new Text('1234');
}
},
FairWidget烘托进程:
dynamic replaceMethod(Map? methodMap, String? exp) {
var body;
if (methodMap != null && exp != null && isFuncExp(exp)) {
body = methodMap[subFunctionName(exp)];
}
return body;
}
调用methodMap 中的Text办法.不会履行js函数
"medalsInfoWidget4": {
"className": "Text",
"pa": [
"1234"
]
}
别的转换成更多的也是相同。
//build办法
Widget build(BuildContext context) {
// ...
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: medalsInfoWidget4(), //这儿会转化成函数: %(medalsInfoWidget4)
),
//...
}
//build外面的办法:将会出现在methodMap
Text medalsInfoWidget4() {
return const Text('1234',style: TextStyle(color: Colors.red,fontSize: 30),);
}
methodMap 更多:
{
className": "Stack",
"na": {
//....
{
"className": "Padding",
"na": {
"padding": {
"className": "EdgeInsets.symmetric",
"na": {
"horizontal": 20
}
},
"child": "%(medalsInfoWidget4)"
}
},
//....
},
"methodMap": {
"medalsInfoWidget4": {
"className": "Text",
"pa": [
"1234"
],
"na": {
"style": {
"className": "TextStyle",
"na": {
"color": "#(Colors.red)",
"fontSize": 30
}
}
}
}
}
}
js文件:
///其实不会履行
medalsInfoWidget4: function medalsInfoWidget4() {
const __thiz__ = this;
with(__thiz__) {
return new Text('1234', {
style: TextStyle({
color: Colors.red,
fontSize: 30
})
});
}
},
即build外的函数转化成 methodMap , 将会依照methodMap 映射表生成的widget而不会走js函数和delegate.
结论:
GestureExpression @开头的,bindFunctionOf 调用的 return _functions?[funcName];
仍是匹配到 FunctionExpression % 开头的 runFunctionOf调用的 _functions?[funcName]?.call();
在履行时,delegate都是不支撑带参数。
- 所以遇到需求带参数时,需求用其他办法代替。
比如在delegate中 经过调用runtime?.variablesSync 和 runtime?.invokeMethodSync 获取js运转时的变量或许调用js函数。实例为:
var invokeMethodSync = runtime?.variablesSync(pageName, {
'medalsInfo': null,
'noMedalsIcon': null,
'noMedalsName': null,
});
var json = jsonDecode(invokeMethodSync!);
var result = json['result'];
或许调用
var invokeMethodSync =
runtime?.invokeMethodSync(pageName, 'getScoreTip', null);
var json = jsonDecode(invokeMethodSync!);
var tip = json['result']['result'];
- 运用jsPlugin。可以运用经过插件可以传递更多参数
- js函数里没有办法再调用delegate了,可以用jsPlugin
- delegate是fair一期的产物,原本就不支撑传参。delegate要支撑传参比较复杂
- jsPlugin context不能传参,需求想办法内置到jsPlugin的dart部分
- plugin回调暂时不能支撑同步调用,现在都是异步的