You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
产生类似这样的snabbdom函数字符串h('div#container.two.classes',{on: {click: someFn}},[h('span',{style: {fontWeight: 'bold'}},'This is bold'),h('h1',strVar),'this is string',h('a',{props: {href: '/foo'}},'I\'ll take you places!')])
exportfunctionparseText(text: string,re: string){if(!re.test(text)){return}consttokens=[]letlastIndex=re.lastIndex=0letmatch,index,tokenValuewhile((match=re.exec(text))){index=match.index// push text tokenif(index>lastIndex){tokenValue=text.slice(lastIndex,index)tokens.push(JSON.stringify(tokenValue))}// tag tokenvarexp=match[1].trim()tokens.push(exp)lastIndex=index+match[0].length}if(lastIndex<text.length){tokenValue=text.slice(lastIndex)tokens.push(JSON.stringify(tokenValue))}return{expression: tokens.join('+'),}}
所以根据AST语法树生成render函数字符串的 递归 处理代码如下:
functioncreateRenderStr(ast: ASTNode): string{
let str: string=""if(ast.type==1){str=createRenderStrElemnet(ast)}elseif(ast.type==3){str=createRenderStrText(ast)}else{warn(`wrong type:${ast.type}`)}returnstr}functioncreateRenderStrElemnet(node: any): string{log('createRenderStrElemnet',node)
let str: string='h('+JSON.stringify(node.tag)letattrs=node.attrsMapif(attrs){str+=',{'// why not use for..in, see eslint `no-restricted-syntax`Object.keys(attrs).every(attrname=>{// str += JSON.stringify(attrname) + '=' + JSON.stringify(attrs[attrname]) + ' '})str+='}'}if(node.children){str+=',['node.children.forEach(child=>{str+=createRenderStr(child)+','})str+=']'}str+=')'returnstr}functioncreateRenderStrText(node: any): string{returnnode.text}
取得了语法树之后,分三步。
生成函数字符串
我们使用
snabbdom
来产生和处理我们的虚拟dom,所以我们需要把AST生成类似下面的render函数字符串。这里只有一个h函数,实际上VUE有多个函数,分别为
filter函数
,如message | capitalize | wrap('-')
会编译成_f("wrap")(_f("capitalize")(message),'-')
这里的h相当于vue的 _c。
现在还没有处理class和attribute,所以代码很简单,一个递归即可。
处理字符串类型的时候,需要把它解析为变量。就是
需要处理为
最后的this我们提取到外面
with(this)
, 调用的时候用call
绑定this到我们自己的实例上。使用的 正则表达式。代码来自vue
所以根据AST语法树生成render函数字符串的 递归 处理代码如下:
相当简单清晰,有没有??
生成函数
使用 new Function,参考 这里
生成之后,保存到实例的
$render
上如何调用
大家注意到,我们生成的函数是没有指定参数的。调用的时候使用call绑定当前的实例到this上,这就是为什么渲染函数前面有个
with(this)
vue里面处理传入当前实例,还会把
$createElement
函数传入,一开始没有太明白,后面想应该是自定义渲染函数render函数的时候需要用到的。这个自定义render函数我们后面再支持,到时候再加,目前就一个当前实例即可。最终效果
测试代码
Xiao/example/helloworld.html
模板
生成的渲染函数字符串
生成的render函数
The text was updated successfully, but these errors were encountered: