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

2023-11-24  本文已影响0人  我是小胡胡123

先看一个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

上一篇 下一篇

猜你喜欢

热点阅读