美文网首页
2023-11-20 58Fair 动态界面渲染表达式解析

2023-11-20 58Fair 动态界面渲染表达式解析

作者: 我是小胡胡分胡 | 来源:发表于2023-11-24 17:30 被阅读0次

    先看一个JSON文件:

    {
      "className": "Text",
      "pa": [
        "^(_platform)"
      ],
      "methodMap": {},
      "digest": "4dc31e6d32f06c9fc22e1ca274b79f15"
    }
    

    这个就是咱们动态界面的布局结构。
    通过FairWidget动态解析映射成flutter widget

    今天咱们主要研究的是^这个符号的解析过程。

    出了^这个符号之外,fair框架一共提供了8种规格的正则表达式5个特殊符号来做区分。这5个符号分别是:

    # @ ¥ % ^

    下面一探究竟:

    ComponentExpression(),
    InlineExpression(),
    InlineObjectExpression(),
    WidgetParamExpression(),
    FunctionExpression(),
    GestureExpression(),
    PropValueExpression(),
    ValueExpression(),

    表达式遍历

    遍历表达式列表, 遍历顺序:

     final List<Expression> _expressions = [
        ComponentExpression(),
        InlineExpression(),
        InlineObjectExpression(),
        WidgetParamExpression(),
        FunctionExpression(),
        GestureExpression(),
        PropValueExpression(),
        ValueExpression(),
      ];
    

    var r = proxyMirror?.evaluate(context, bound, v, domain: domain);

    class ProxyMirror with P {
    ///....
      W<dynamic> evaluate(
        BuildContext? context, BindingData? bindingData, String text, {Domain? domain}) {
            var pre = '';
            for (var exp in _expressions) {
              
              // 如果当前表达式不匹配,则继续下一个表达式
              if (!exp.hitTest(text, pre)) {
                continue;
              }
    
              var result = exp.onEvaluate(this, bindingData, domain, text, pre);
    
              // 更新 pre 以便下一轮迭代使用
              pre = result.exp??'';
    
    
              if (result.valid()) {//它检查 data 是否为非空字符串,或者它是否不为null。
                       //检查数据有效性 有效直接返回退出循环
                return W<dynamic>(result.data, result.needBinding);
              }
            }
            return W<dynamic>(text, false);
      }
    }
    

    result.valid()方法实现:

    它检查 data 是否为非空字符串,或者它是否不为null。

    bool valid() {
      if (data is String) {
        String strData = data as String;
    
        return strData.length > 0;
      }
      return data != null;
    }
    

    ValueExpression

    
    class ValueExpression extends Expression {
      @override
      R onEvaluate(
          ProxyMirror? proxy, BindingData? binding, Domain? domain, String? exp, String? pre) {
        var prop = binding?.bindDataOf(pre ?? '') ??
            binding?.modules?.moduleOf(pre ?? '')?.call();
        if (prop is ValueNotifier) {
          var data = _PropBuilder(pre ?? '', prop, proxy, binding);
          binding?.addBindValue(data);
          return R(data, exp: exp, needBinding: true);
        }
        return R(prop, exp: exp, needBinding: false);
      }
    
      @override
      bool hitTest(String? exp, String? pre) {
        return true;
      }
    }
    
    

    binding?.bindDataOf

      dynamic bindDataOf(String key) {
        if (_values != null && _values![key] != null) {
          return Function.apply(_values![key]!, null);
        } else if (data != null && data![key] != null) {
          return data![key];
        }
        return functionOf(key);
      }
    

    BindingData

    这个 bindData 是一个FairApp级别的AppState, 是一个根级别的Widget 用来实现子节点数据共享

      Future<dynamic> register(FairState state) async {
        log('register state: ${state.state2key}');
    
        _mFairHandler.register(state);
    
        var delegate = state.delegate;
    
        delegate.setRunTime(runtime);
    
    
        // await delegate.bindAll({});
    
    
        bindData.putIfAbsent(
          
          state.state2key,
    
          () => BindingData(
            
            modules,
    
            functions: delegate.bindFunction(),
    
            values: delegate.bindValue(),
          ),
    
        );
    
        return Future.value(null);
      }
    
    
    

    内置values 实现:

      void bindBaseValue() {
        _bindValuesMap.addAll({'_platform': () => 'Fair v$fairVersion'});
      }
    
    

    内置functions:

      void bindBaseFunc() {
        _bindFunctionsMap['runtimeInvokeMethod'] 
        _bindFunctionsMap['runtimeInvokeMethodSync']  
        _bindFunctionsMap['runtimeParseVar'] 
      }
    
    

    以及:

      Map<String, Function> bindFunction() {
        var func = super.bindFunction();
        func['Sugar.paddingTop'] = (props) => Sugar.paddingTop(context);
        func['Sugar.paddingBottom'] = (props) => Sugar.paddingBottom(context);
        func['Sugar.height'] = (props) => Sugar.height(context);
        func['Sugar.width'] = (props) => Sugar.width(context);
        func['Sugar.requestFocus'] = (props) => Sugar.requestFocus(context);
        func['Sugar.onTapEmpty'] = (props) => Sugar.onTapEmpty();
        return func;
      }
    

    传递data:

      Widget _convert(BuildContext context, Map map, Map? methodMap, {Map? data}) {
        
        var app = FairApp.of(context);
        
        var bound = app?.bindData[page];
    
    
        if (data != null && data.isNotEmpty) {
          log('[Fair] binding data => $data');
    
          bound ??= BindingData(app?.modules);
    
          bound.data = data;
        }
    
        //....
      }
    }
    

    PropValueExpression

    class PropValueExpression extends Expression {
      @override
      R onEvaluate(
          ProxyMirror? proxy, BindingData? binding, Domain? domain, String? exp, String? pre) {
        var expression = exp?.substring(2, exp.length - 1);
        var prop = binding?.bindRuntimeValueOf(expression ?? '');
        return R(prop, exp: expression, needBinding: false);
      }
    
      @override
      bool hitTest(String? exp, String? pre) {
        return RegExp(r'\^\(\w+\)', multiLine: false).hasMatch(exp ?? '');
      }
    }
    
    

    binding?.bindRuntimeValueOf(expression ?? '');

      dynamic bindRuntimeValueOf(String name) {
        // _delegateValues优先级高于JS,如果要使用JS的变量,需要重命名变量
        if (_values?[name] == null) {
          var result = _functions?['runtimeParseVar']?.call({name: ''});
          var value = jsonDecode(result);
          if (value['result'][name] != null) {
            return value['result'][name];
          }
        } else {
          if (_values != null && _values?[name] != null) {
            return Function.apply(_values![name]!, null);
          }
        }
        return null;
      }
    
    

    FairApp保存全局状态 自widget可以共享数据。

      static FairApp? of(BuildContext? context, {bool rebuild = false}) {
        return rebuild ? context?.dependOnInheritedWidgetOfExactType<FairApp>() : context?.findAncestorWidgetOfExactType<FairApp>();
      }
    
    表达式类 字面量实例
    ComponentExpression #(xxx)
    InlineObjectExpression $xxx
    InlineExpression ${xxx}
    WidgetParamExpression $(widget.xxx)
    FunctionExpression %(xxx)、支持嵌套:%(xxx(^(xxx1),^(xxx2))) 、特殊名字 index:%(xxx(^(index))
    GestureExpression @(xxx)
    PropValueExpression ^(xxx)
    ValueExpression 任何其他字符串

    总结

    1、2、3

    相关文章

      网友评论

          本文标题:2023-11-20 58Fair 动态界面渲染表达式解析

          本文链接:https://www.haomeiwen.com/subject/ghqmwdtx.html