既然要讲 生命周期,那渲染过程得先了解下。
数据绑定
Vue 文本插值
在 Vue 中,最基础的模板语法是数据绑定,例如:
<div>{{ data }}</div>
这里绑定了一个 msg 的变量,开发者在 Vue 实例 data 中绑定该变量:
new Vue({
data: {
data: "测试文本"
}
});
最终页面展示内容为<div>测试文本</div>。
数据绑定的实现
这种使用双大括号来绑定变量的方式,我们称之为数据绑定。它是怎么实现的呢,数据绑定的过程其实不复杂:
1、解析语法生成 AST。
2、根据 AST 结果生成 DOM。
3、将数据绑定更新至模板。
上述这个过程,是模板引擎在做的事情。我们来看看上面在 Vue 里的代码片段<div></div>
,我们可以解析后获得这样一个 AST 对象:
thisDiv = {
dom: {
type: "dom",
ele: "div",
nodeIndex: 0,
children: [{ type: "text", value: "" }]
},
binding: [{ type: "dom", nodeIndex: 0, valueName: "data" }]
};
这样,我们在生成一个 DOM 的时候,同时添加对data的监听,数据更新时我们会找到对应的nodeIndex,更新值:
// 假设这是一个生成 DOM 的过程,包括 innerHTML 和事件监听
function generateDOM(astObject) {
const { dom, binding = [] } = astObject;
// 生成DOM,这里假装当前节点是baseDom
baseDom.innerHTML = getDOMString(dom);
// 对于数据绑定的,来进行监听更新吧
baseDom.addEventListener("data:change", (name, value) => {
// 寻找匹配的数据绑定
const obj = binding.find(x => x.valueName == name);
// 若找到值绑定的对应节点,则更新其值。
if (obj) {
baseDom.find(`[data-node-index="${obj.nodeIndex}"]`).innerHTML = value;
}
});
}
// 获取DOM字符串,这里简单拼成字符串
function getDOMString(domObj) {
// 无效对象返回''
if (!domObj) return "";
const { type, children = [], nodeIndex, ele, value } = domObj;
if (type == "dom") {
// 若有子对象,递归返回生成的字符串拼接
const childString = "";
children.forEach(x => {
childString += getDOMString(x);
});
// dom对象,拼接生成对象字符串
return `<${ele} data-node-index="${nodeIndex}">${childString}</${ele}>`;
} else if (type == "text") {
// 若为textNode,返回text的值
return value;
}
}
Vue 简介
看看这些模板引擎都做了啥事,原本就是一个<div>
,经过 AST 生成一个对象,最终还是生成一个<div>
,这是多余的步骤吗?不是的,在这个过程中我们可以实现一些功能:
- 排除无效 DOM 元素,并在构建过程可进行报错
- 使用自定义组件的时候,可匹配出来
- 可方便地实现数据绑定、事件绑定等,具备自动更新页面的功能
- 为虚拟 DOM Diff 过程打下铺垫
- HTML 转义(预防 XSS 漏洞)
所以 Vue 它只是一个模板引擎吗?怎么说呢,模板引擎可能是我们选择框架的原因里最重要的一个,毕竟如果没有框架的话,所有上述这些很好用的能力都需要自己搭建,不然开发效率会很受影响。
我们看看 Vue 官方的介绍:
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue
的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
关于 Vue 和其他框架的对比,可以看看官方文档-对比其他框架 (opens new window)。易于上手这块,是大多数人都比较认可的,框架的性能也不错,这也是技术选型中比较重要的一些考虑。
我们知道在 Vue 中要渲染一块页面内容的时候,会有这么几个过程:
1). 解析语法生成 AST。
2). 根据 AST 结果,完成 data 数据初始化。
3). 根据 AST 结果和 data 数据绑定情况,生成虚拟 DOM。
4). 将虚拟 DOM 生成真正的 DOM 插入到页面中,此时页面会被渲染。
当我们绑定的数据进行更新的时候,又会产生以下这些过程:
5). 框架接收到数据变更的事件,根据数据生成新的虚拟 DOM 树。
6). 比较新旧两棵虚拟 DOM 树,得到差异。
7). 把差异应用到真正的 DOM 树上,即根据差异来更新页面内容。
当我们清空页面内容时,还有: 8). 注销实例,清空页面内容,移除绑定事件、监听器等。
所以在整个页面或是组件中,我们会有以下的一些关键的生命周期钩子: