1. 模板编译
Vue的模板编译就是将模板字符串转换为渲染函数的过程。具体来说,当组件的生命周期执行到created和beforeMounted之间时,Vue会将模板(template)编译成渲染函数(render),render函数是一个纯JavaScript函数,由with
语句构成,它接收一个Vue组件实例作为参数。当render函数执行时会调用h函数,生成虚拟DOM节点(vnode)。
下面给出了常见的template模板以及模板编译后的结果:
- 插值
`<p>{{message}}</p>`
with(this){return _c('p',[_v(_s(message))])}
// _c 表示 createElement 也就是h函数 返回vnode
// _v 表示 createTextVNode
// _s 表示 toString
- 表达式
`<p>{{flag ? message : 'no message found'}}</p>`
with(this){return _c('p',[_v(_s(flag ? message : 'no message found'))])}
- 属性和动态属性
`<div id="div1" class="container">
<img :src="imgUrl"/>
</div>`
with(this){
return _c('div',
{staticClass:"container",attrs:{"id":"div1"}},
[_c('img',{attrs:{"src":imgUrl}})]
)
}
- 条件
`<div>
<p v-if="flag === 'a'">A</p>
<p v-else>B</p>
</div>`
with(this){
return _c('div',[(flag === 'a')?_c('p',[_v("A")]):_c('p',[_v("B")])])
}
- 循环
`<ul>
<li v-for="item in list" :key="item.id">{{item.title}}</li>
</ul>`
with(this){
return _c('ul',_l((list),
function(item){return _c('li',{key:item.id},
[_v(_s(item.title))])}),0
)
}
- 事件
`<button @click="clickHandler">submit</button>`
with(this){return _c('button',{on:{"click":clickHandler}},[_v("submit")])}
- v-model
`<input type="text" v-model="name">`
with(this){
return _c('input',
{
directives:[{name:"model", rawName:"v-model", value:(name), expression:"name"}],
attrs:{"type":"text"},
domProps:{"value":(name)},
on:{"input":
function($event){
if($event.target.composing)return;
name = $event.target.value
}
}
}
)
}
2. 组件渲染和更新
Vue组件渲染和更新的过程简单地概况为以下几个步骤:
- 初始化组件实例:在渲染一个组件之前,Vue会创建一个组件实例,并将组件的选项对象进行合并、处理,最终形成一个组件实例的配置对象。
- 渲染组件:Vue将组件实例的配置对象转化为一个渲染函数,并执行该渲染函数,生成一个虚拟DOM树。此时,Vue会对虚拟DOM树进行初次渲染,将组件显示在页面上。
- 监听数据变化:当组件实例中的响应式数据发生变化时,Vue会立即检测到这些变化,并重新计算组件的渲染函数,生成一个新的虚拟DOM树。
- 对比新旧虚拟DOM树:Vue会将新生成的虚拟DOM树和上一次渲染时生成的虚拟DOM树进行比较,找出需要更新的部分。
- 更新组件:Vue会将需要更新的部分进行精细化地修改,使组件达到更新的效果。如果有需要,Vue会重新渲染整个组件。