因为直接操作真实的 DOM 会比较影响效率。所以 vue 使用了 虚拟DOM(VNode)来描述要渲染的内容。
它是一个 js 对象,比如:
const vnode = {
tag: "h1",
children: [
{ tag: undefined, text: "Hello World"}
]
}
另外 vue 的模板也不是真实 DOM,它会被编译为渲染函数render
:用来返回虚拟 DOM 树的函数。
<div id="app">
<h1>第一个vue应用:{{title}}h1>
<p>描述:{{author}}p>
div>
render
函数执行会返回类似下面的结构(虚拟 DOM 树),并基于它创建实际的 DOM 节点。
{
tag: "div",
children: [
{ tag: "h1", children: [ { text: "第一个vue应用:Hello World" } ] },
{ tag: "p", children: [ { text: "描述:desc" } ] }
]
}
当依赖数据发生变化后,会引发重新渲染。vue 会比较新旧 VNode tree 并找出差异,仅把差异部分(必要的更新)应用到真实的 DOM 树中。
所以,在 vue 中要得到最终的页面,必须先生成一个虚拟DOM树。逻辑如下:
vue 官网参考
1,有 render
函数则运行它。
2,否则判断有没有 template
属性,有则将 template
配置做为模板,编译为 render
函数来运行。
3,否则将 el
绑定的DOM元素作为模板,编译为 render
函数来运行。
下面3个例子,渲染结果相同。
举例1,只有 render
函数
<body>
<div id="app">div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: "#app",
data: {
title: "你好 vue",
desc: "第一个 vue 应用",
},
render(h) {
return h("div", [
h("h1", this.title),
h("p", `描述:${this.desc}`),
]);
},
});
script>
body>
举例2,只有 template
属性
<body>
<div id="app">div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: "#app",
data: {
title: "你好 vue",
desc: "第一个 vue 应用",
},
template: `
{{title}}
描述:{{desc}}
`,
});
script>
body>
举例3,使用 el
对应的 outerHTML
作为模板
<body>
<div id="app">
<div>
<h1>{{title}}h1>
<p>描述:{{desc}}p>
div>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
const vm = new Vue({
el: "#app",
data: {
title: "你好 vue",
desc: "第一个 vue 应用",
},
});
script>
body>
以上。