Vue中模板渲染原理
1、概念
- 模板:本质字符串。
- 与字符串的区别:
- 有逻辑(vue中有v-if、v-for)
- 嵌入js变量({{变量}})
- 需要转化为html,页面才会识别并正确解析。
2、实现过程
- 过程:模板(字符串)解析成render函数
---->
render函数执行返回JS的vnode的结构,是如何实现嵌入变量和执行逻辑。转化为html则由updateComponent函数调用patch方法实现。 - 例子1(只有js变量、无涉及逻辑):
<div id="app">
<p>{{price}}</p>
</div>
- 经过vue模板生成的结果(实现了模板转化为JS的vnode并填充data中的变量):
// 此处vm为VUE的实例
//在控制台可以打印vm._c创建元素的,vm_v创建文本节点,vm_s是用来转化为字符串的
vm._c(
'div',
{
attrs: {'id': 'app'}
},
[
vm._c('p', [vm._v(vm._s(vm.price))])
]
)
用法备注:
- vm._c是基于snabbdom中的h(‘节点标签’,{属性、特性、事件},[子节点]/文本)实现的,是用来创建vnode的。vue中的render函数,实现了传入Vue实例后返回vnode的功能。
- vm._v是用来创建文本节点或实现换行的。
- vm._s是用来转化字符串的。
- render内部实际是使用with(vm),这样在内部就可以直接使用_c、_v、_s和data中的属性
- 例子2(以todolist为例子,涉及v-for逻辑):
<div id="app">
<div>
<input v-model="inputValue" type="text" />
<button v-on:click="handleClick">submit</button>
</div>
<div>
<ul>
<li v-for='item of list'>
{{item}}
</li>
</ul>
</div>
</div>
- v-for逻辑实现是通过v._l()方法,生成对应的li结构后返回数组,将此数组作为ul节点的子节点。以下是返回的vnode:
with(vm) {
_c(
// 第一层(根元素)div
'div',
{
attrs:{"id":"app"}
},
// 包含所有子节点的数组
[
_c(
// 第二层第一个div(包含input、button以及其attrs、绑定事件还有值)
'div',
[
_c(
'input',
{
// v-model数据的双向绑定
directives:[
{
name:"model",
rawName:"v-model",
value:(inputValue),
expression:"inputValue"
}
],
attrs:{
"type":"text"
},
domProps:{
"value":(inputValue)
},
on:{
// 监听input内容,数据改变时,让Model层的数据更新
"input":function($event){
if($event.target.composing)return;
inputValue=$event.target.value
}
}
}
),
_v(" "),
_c(
'button',
{
// 渲染绑定事件
on:{
"click":handleClick
}
},
[_v("submit")]
)
]),
_v(" "),//创建空文本节点,用于换行
_c(
// 第二层第二个div(包含ul、li,其中li是通过for循环生成的)
'div',
[
_c(
// ul标签
'ul',
// _l返回的是包含子元素的数组
_l((list),function(item){
// v-for循环,实际是返回所有创建li标签的数组
return _c(
'li',
[
_v("\n "+_s(item)+"\n ")
]
)
}),0)//数字表示list有多少项,要返回多少个li
]
)
]
)}
}
3、总结:
- 个人理解(有误的话,欢迎指正):
1、 模板解析成render函数---->
返回JS模拟的虚拟DOM结构:模板是一段字符串,模板解析生成render函数,执行render函数返回为vnode,vnode表明了各个节点的层级关系、特性、样式、绑定的事件。
2、 vnode---->
html:通过 updateComponent函数调用vm._update()
传入vnode,利用基于snabbdom的patch()方法改造的生成真实DOM节点并渲染页面。
注:vm.__patch__
:初次渲染时,调用vm.__patch__(containe, vnode)
,生成真实的DOM结构渲染到容器中。re-render时,调用vm.__patch__(vnode, newVnode)
利用diff算法对比新旧vnode之间的差异,生成需要更新的真实DOM,渲染到容器的对应位置。