function processAst(ast, scope) { ... .(.assign({}, scope, { [)) }) } ... }
就简单通过一个递归,就可以把作用域一直传递下去了。
Filter 功能实现实现上面功能后,组件就已经具备基本的模板渲染能力,不过在用模板引擎的时候,还有一个很常用的功能就是 filter 。一般来说 filter 的使用方式都是这这样 {{ test | filter1 | filter2 }},这个的实现也说一下,这一块的实现我参考了 vue 的解析的方式,还是蛮有意思的。
还是举个例子:
{{ test | filter1 | filter2 }}在构建 AST 的时候,就可以获取到其中的test | filter1 | filter2,然后我们可以很简单的就获取到 filter1 和 filter2 这两个字符串。起初我的实现方式,是把这些 filter 字符串扔进 ast 节点的 filters 数组中,在渲染的时候再一个一个拿出来处理。
不过后来又觉得为了性能考虑,能够在 AST 阶段就能做完的工作就不要放到渲染阶段了。因此就改成 vue 的方法组合方式。也就是把上面字符串变成:
_$f('filter2', _$f('filter1', test))预先用个方法包裹起来,在渲染的时候,就不需要再通过循环去获取 filter 并且执行了。具体实现如下:
filterSplitRE (exprmatches (matches) { const arr = matches[0].trim().split(filterSplitRE); result ..((name === 'safe') { escape result nameresult)escape result
上面还有一个就是对 safe 的处理,如果有 safe 这个 filter ,就不做 escape 了。完成这个之后,有 filter 的 variable 都会变成_$f('filter2', _$f('filter1', test))这种形式了。因此,此前的 computedExpression 方法也要做一些改造了。
filter ()(str)(objexpressionfuncString methodBodyfunc (funcString)result (result result : result(e) (e
其实也是很简单,就是在 new Function 的时候,多传入一个获取 filter 的方法即可,然后有 filter 的 variable 就能被正常识别解析了。
至此,AST 构建、AST 到 html 的转换、Filter 的实现,都已经基本讲解完成。
贴一下自己实现的一个模板引擎轮子:https://github.com/whxaxes/mus
算是实现了大部分模板引擎该有的功能,欢迎各路豪杰 star 。