本文持续记录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:

58fairDelegate方法调用规则-携带参数使用问题总结

调用2:

58fairDelegate方法调用规则-携带参数使用问题总结

调用3:

58fairDelegate方法调用规则-携带参数使用问题总结

调用4:

58fairDelegate方法调用规则-携带参数使用问题总结

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;
  }

58fairDelegate方法调用规则-携带参数使用问题总结

调用methodMap 中的Text办法.不会履行js函数

"medalsInfoWidget4": {
      "className": "Text",
      "pa": [
        "1234"
      ]
    }

58fairDelegate方法调用规则-携带参数使用问题总结

别的转换成更多的也是相同。


//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回调暂时不能支撑同步调用,现在都是异步的