一、处理template里的或者html字符串通过parse()成为ast语法树。
parse():
parseHTML(): 这2个函数是:处理html的过程,通过遍历html元素,得到所有的元素对象,分别区分处理元素,属性,指令等ast语法。具体结构如下:
1.元素类型 1.或3
2.元素tag值。div
3 .属性值:a.数组类型(attrsList),b.对象类型。(attrsMap)
4 .父元素: parent
5.子元素: children
6.classBinding。样式的名称key值。
- 静态的class值。即原来就固定写好的值。比如:staticClass: ""static""
-
rawAttrsMap:这个不是很明白。指令吗?
以下这个图 是ast部分语法图
二、再将ast语法树,通过Transform()处理vue特有语法,再通过genrate()编译成 render 函数。。运行_c的时候就会读取响应的data值。然后再作对应变量值的对应渲染树,watcher
generate(ast, options):
genElement(ast) : '_c("div")':主要处理ast元素里面的指令,v-if,slots等。涉及多个处理指令的函数如下
这上面2个函数是处理上面的ast结构的
return genStatic(el, state)
return genOnce(el, state)
return genFor(el, state)
return genIf(el, state)
return genChildren(el, state) || 'void 0'
return genSlot(el, state)
然后在把上面的ast 经过var code = generate(ast, options);处理得到可执行的code。
通过下面2个函数,加上上面的ast入参,产生如下。
下面的_c里面包含很多变量,关于data里的,props,
//genElement产出的code值如下:
"_c('div',{class:[activeClass, errorClass]},[_v("hello ,喂。。数组语法 。")])"
"_c('div',{staticClass:"static",class:{ active: isActive, 'text-danger': hasError }},[_v("\n 对象方式\n ")])"
"_c('div',{class:[isActive ? activeClass : '', errorClass]},[_v("数组形式,的三元运算")])"
"_c('div',{attrs:{"id":"demo"}},[_c('form',{attrs:{"id":"search"}},[_v("\n Search "),_c('input',{directives:[{name:"model",rawName:"v-model",value:(searchQuery),expression:"searchQuery"}],attrs:{"name":"query"},domProps:{"value":(searchQuery)},on:{"input":function($event){if($event.target.composing)return;searchQuery=$event.target.value}}})]),_v(" "),_c('demo-grid',{attrs:{"data":gridData,"columns":gridColumns,"filter-key":searchQuery}})],1)"
// 编译字符串。。。
function baseCompile(
template,
options
) {
var ast = parse(template.trim(), options);
optimize(ast, options);
var code = generate(ast, options);
return {
ast: ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
}
相当于以上2个步骤是vue暴露出来的接口:Vue.compile( template )
Vue.compile( template )
用法如下:适用于要编程式写法代替html模板写法。
var res = Vue.compile('<div><span>{{ msg }}</span></div>')
var a = new Vue({
data: {
msg: 'hello'
},
render: res.render,
staticRenderFns: res.staticRenderFns
})
a.$mount('#app');
等同于vue.compile方法内部的使用方式如下(摘用了vue.$mount的里面部分源码):
var ref = compileToFunctions(template, {
shouldDecodeNewlines: shouldDecodeNewlines,
delimiters: options.delimiters
}, this);
//得到一个 渲染dom的函数
var render = ref.render;
var staticRenderFns = ref.staticRenderFns;
options.render = render;
options.staticRenderFns = staticRenderFns;
三、vm._render()产生虚拟dom
上面通过了ast,_c()写法 然后产生了虚拟dom.
四。vm.$el = vm.patch(prevVnode, vnode);变成了真实的dom.
vm._update: 对比虚拟dom的过程
vm._render: 生成虚拟dom的过程
patch成真实dom脑图链接:
整体流程如下:
Template:
html代码— 通过parse()
Ast:
语法树,— 变成JS 描述的DOM。—> transform()
Transform:
vue特有的语法转化
Generate:
生成最终的执行代码
上图: