先看一个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
网友评论