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

本文继续记录fair界面的不同写法对fair delegate方法调用的处理的源码实现过程。 fair delegate

FairWidget界面解析2种正则匹配方式

在FairWidget 的build方法的界面解析过程 两种方式的写法将会走不同的流程。

  • GestureExpression

正则:

python 复制代码
RegExp(r'@(.+)', multiLine: false).hasMatch(exp ?? '');

将使用bindFunctionOf方法。

  • FunctionExpression

正则:

python 复制代码
RegExp(r'%(.+)', multiLine: false).hasMatch(exp ?? '');

将使用runFunctionOf 方法。

GestureExpression方式

这种方式为@(medalsInfoWidget) @开头的这种样式。

写法为:

css 复制代码
 Padding(
              padding: const EdgeInsets.symmetric(horizontal: 20),
              child: Builder(
                builder: medalsInfoWidget,
              ),
            ),
            
  Widget medalsInfoWidget(context) {
    return Container();
  }

他转化成json内容为:

css 复制代码
    {
              "className": "Padding",
              "na": {
                "padding": {
                  "className": "EdgeInsets.symmetric",
                  "na": {
                    "horizontal": 20
                  }
                },
                "child": {
                  "className": "Builder",
                  "na": {
                    "builder": "@(medalsInfoWidget)"
                  }
                }
              }
            },
            
             "medalsInfoWidget": {
      "className": "Container"
    }

JS文件中这种方式将不会有medalsInfoWidget js函数生成。

运行过程中: 将会匹配到GestureExpression 执行bindFunction逻辑:

kotlin 复制代码
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方法
  }
}

对应我们的代理方法实现为:

javascript 复制代码
  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的写法为:

css 复制代码
   Padding(
              padding: const EdgeInsets.symmetric(horizontal: 20),
              child: medalsInfoWidget2(),
          
            ),
 
     // 不能写不支持的返回值类型,返回值不能是widget这种js不支持的类型。写返回值不会生成JS方法,也不会走delegate
  medalsInfoWidget2() {}

转化成json为

css 复制代码
    {
              "className": "Padding",
              "na": {
                "padding": {
                  "className": "EdgeInsets.symmetric",
                  "na": {
                    "horizontal": 20
                  }
                },
                "child": "%(medalsInfoWidget2)"
              }
            },

js方法为:

javascript 复制代码
     medalsInfoWidget2: function medalsInfoWidget2() {
                    const __thiz__ = this;
                    with(__thiz__) {}
                },

对应我们的代理方法实现为:

javascript 复制代码
  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})

ini 复制代码
 _functions?[funcName]?.call();
 

runFunctionOf完整实现为:

kotlin 复制代码
 
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的方法也是不能支持携带参数
  }
} 

结论:

GestureExpression @开头的,bindFunctionOf 调用的 return _functions?[funcName];

还是匹配到 FunctionExpression % 开头的 runFunctionOf调用的 _functions?[funcName]?.call();

在执行时,delegate都是不支持带参数。

  • 所以遇到需要带参数时,需要用其他方法代替。

比如在delegate中 通过调用runtime?.variablesSync 和 runtime?.invokeMethodSync 获取js运行时的变量或者调用js函数。实例为:

csharp 复制代码
var invokeMethodSync = runtime?.variablesSync(pageName, {
  'medalsInfo': null,
  'noMedalsIcon': null,
  'noMedalsName': null,
});
var json = jsonDecode(invokeMethodSync!);
var result = json['result'];
 

或者调用

ini 复制代码
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回调暂时不能支持同步调用,现在都是异步的
相关推荐
周胡杰41 分钟前
鸿蒙接入flutter环境变量配置windows-命令行或者手动配置-到项目的创建-运行demo项目
javascript·windows·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
teacher伟大光荣且正确43 分钟前
Qt Creator 配置 Android 编译环境
android·开发语言·qt
程序猿阿伟3 小时前
《React Native与Flutter:社交应用中用户行为分析与埋点统计的深度剖析》
flutter·react native·react.js
飞猿_SIR3 小时前
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
android·音视频
HumoChen994 小时前
GZip+Base64压缩字符串在ios上解压报错问题解决(安卓、PC模拟器正常)
android·小程序·uniapp·base64·gzip
沙振宇8 小时前
【HarmonyOS】ArkTS开发应用的横竖屏切换
android·华为·harmonyos
橙子199110169 小时前
Kotlin 中的作用域函数
android·开发语言·kotlin
zimoyin9 小时前
Kotlin 懒初始化值
android·开发语言·kotlin
枣伊吕波10 小时前
第六节第二部分:抽象类的应用-模板方法设计模式
android·java·设计模式
萧然CS10 小时前
使用ADB命令操作Android的apk/aab包
android·adb