记录下vue原理中的一些知识点
本文最后更新于 2025-01-25,文章内容可能已经过时。
生命周期
生命周期,就是vue实例从创建到销毁的一个过程,主要分为创建、挂载、更新、销毁四个阶段!
大致流程就是:
vue实例初始化
初始化响应式数据
获取模版节点
对模版进行编译
挂载模版替换$el元素
数据发生变化,找到属性Dep依赖中所存放的Watcher,通知并更新
diff新旧虚拟dom比对,找到最小差异,重新渲染真实DOM

beforeCreate:实例创建后, 在数据初始化之前调用!- 创建实例,会
初始化Events事件,以及生命周期!
- 创建实例,会
created:响应式数据初始化后调用!- 其次会
初始化响应式数据,在这个阶段,会对options中的数据进行劫持,并通过defineProperty属性描述符,来对每一个属性添加get和set方法,以及会为每一个属性添加一个Dep依赖对象,方便后面数据变化时通知和更新操作!
- 其次会
beforeMount: 挂载dom之前调用- 需要获取模版(
template),根据el,或者template来找到对应的模版,进行模版编译!
- 需要获取模版(
mounted:挂载dom后,调用该钩子函数,- 此时会
获取编译好的模版,来替换vue中的$el元素,进行挂载!
- 此时会
beforeUpdate:当响应式数据发生变化时,dom更新之前,会调用此钩子函数,- 此阶段
dom中的数据还是更新之前的状态!
- 此阶段
updated:dom中的数据更新之后调用,- 此时
dom中的数据已被更新!
- 此时
beforeDestory:在实例销毁前调用- 此时还
可以访问实例中的属性和方法,以及dom!
- 此时还
destoryed:实例销毁之后,dom已被卸载!
模版渲染原理
在
vue中通常编写的模版,在运行时,会将模版编译为一个render函数,会将一些模版中特殊的语法进行转换,如指令,动态插值表达式等相关特属语法,转换为浏览器能够认识的语法!
<template>
<!--app 静态节点 -->
<div class="app">
<!--动态节点{{}}-->
<span class="name">{{ name }}</span>
<span class="age">{{ age }}</span>
</div>
</template>
<script>
export default{
name: "test",
data(){
return {
name: "张三",
age: 18
}
}
}
</script>模版编译过程:
- 将
模版template转换为AST抽象语法树:AST抽象语法树,就是通过js对象来描述的模版元素以及属性和文本内容!AST抽象语法树,就是将语法表达式,通过对象树的形式来描述该语法内部所包含的内容!AST抽象语法树,js代码解析,vue模版解析,打包构建工具中都用到了AST语法树!
- 对
AST语法树进行静态标记优化:- 将
模版中不涉及到动态内容的节点做静态标记,关注需要动态变化的节点部分,减少不必要的DOM渲染! - 比如
模版中,用到的指令,或者是响应式数据等,其它静态节点元素,会被标记为静态,后期只关注更新动态节点!
- 将
- 生成(
generate)真实dom:diff找到新旧DOM差异,通过Render函数,渲染和更新,替换为真实DOM!
响应式原理
vue中的响应式,就是数据与视图之间的一个绑定关系,当数据发生变化时,vue会通知视图进行更新,而视图中的响应式数据发生变化时,则会更新对应的数据!
MVVM模式
mvvm模式是一种规范,由mvc模式转换而来!
M(Model)代表的数据层,响应式数据!
V(View)代表的是视图层!
VM(Vue)代表的vue实例,主要负责数据层与视图层之间的响应式关系!
Vue2中的响应式
vue2中的的响应式,主要是通过defineProperty方法实现的,该方法用来定义对象属性描述的,可以控制属性一些操作行为(是否可枚举,是否可配置,是否可删除)等相关属性配置,其中还包含了两个方法,get和set方法,当获取对象中对应的属性时,会触发getter操作,当对对象中的属性重新赋值时,会触发setter操作,通过这两个方法,可以有效的监听对象属性"获取"和"编辑"的监听!
响应式数据初始化
在初始化
vue实例时,vue会对options中的数据进行响应式处理,通过Observer方法进行数据劫持,如果是对象或者是数组对象时,会通过迭代的方式调用 defineReactive 方法给每一个属性添加getter和setter方法,最后将数据代理到vue实例上!
class Vue{
construcotr( options ){
this.$options = options;
this.$el = options.el;
this.$data = options.data;
// 数据劫持
Observer( this.$data );
// 将数据代理到vm实例上
Proxy(this)
// 模版编译
complier(this, el);
}
}Observer数据劫持
function observer( obj ){
if( typeof data !== "Object" ){
return
}
for(let key in data){
defineReactive(data, key, data[key]);
}
}defineReactive 添加 get和 set
function defineReactive(target, key, value){
Object.defineProperty(target, key, {
get(){
// 将watcher添加到dep中
if(Dep.target){
Dep.depend();
}
return value;
},
set( val ){
if( value !== val ){
value = val;
}
// 获取Dep依赖,调用watcher回调函数操作
if(Dep.target){
Dep.notify();
}
}
})
}
Dep是vue中的一个依赖对象,主要负责响应式数据依赖收集,当响应式属性值发生变化时,会通知更新操作!
响应式数据:data props computed watch以及props!
依赖收集
依赖指的是响应式数据,比如template模版中动态绑定的属性,或者展示的一些属性,这些都是属于依赖部分, 而这些依赖属性都会绑定一个watcher类,这个watcher类,主要负责监听响应式依赖属性变化的后续更新操作!
<template>
<div class="app">
<!--属性依赖 name age -->
<div>
姓名: {{ name }}
年龄: {{ age }}
体重: {{ weghit }}
</div>
</div>
</template>
<script>
export default{
data(){
return {
name: "张三", // key1 watcher1
age: 18, // key2 watcher2
weghit: 120 // key3 watcher3
}
}
}
</script>另外,
Watcher对象由Dep依赖对象来进行管理,当数据发生变化时,会触发Dep操作,执行对应的Watcher回调函数!
Dep deps = [Watcher1, Watcher2]
Dep deps = [Watcher3]代码实现
Watcher监听响应式数据
class Watcher{
constructor( vm, key, update ){
this.$vm = vm;
this.key = key;
this.updateFun = update;
Dep.target = this; // 将watcher和依赖进行关联
vm[key]; // 触发getter操作
Dep.target = null;
}
updater(){
this.updateFun.call(this, this.$vm[key])
}
}Dep依赖收集
class Dep{
// target 就是每个属性所对应的Watcher对象
static target = null;
constructor(){
this.deps = [];
}
// getter 触发时,如果target存在,将Watcher添加到Deps依赖中
addDeps( dep ){
this.deps.push(dep);
}
// setter 触发时,会执行Watcher中的更新操作
notify(){
this.deps.forEach(watcher => watcher.updater());
}
}defineReactive响应式函数
function defineReactive(target, key, value){
const dep = new Dep();
Object.defineProperty(target, key, {
get(){
// 将watcher添加到dep中
if(Dep.target){
dep.addDeps(Dep.target);
}
return value;
},
set( val ){
if( value !== val ){
value = val;
}
// 获取Dep依赖,调用watcher回调函数操作
if(Dep.target){
dep.notify();
}
}
})
}总结
Watcher:Watcher主要负责响应式数据依赖监听,且每个属性key都会有一个Watcher对象!
Dep:Dep是一个依赖对象,当数据被获取时,dep会将Watcher对象添加到依赖数组中!- 当
数据发生变化时,会遍历依赖数组,执行Watcher对象中的更新操作!
defineReactive:defineReactive主要用来给属性添加getter和setter操作!- 触发
getter时,会调用Dep.addDeps来收集依赖! - 触发
setter时,会调用Dep.notify来更新依赖!
父子组件生命周期执行顺序
在
vue中,父组件和子组件生命周期之间的加载过程,主要是在父组件挂载(beforeMount)之前,会将子组件进行挂载!
加载渲染过程父
beforeCreate-> 父created-> 父beforeMount-> 子beforeCreate-> 子created-> 子beforeMount-> 子mounted-> 父mounted子组件更新过程父
beforeUpdate-> 子beforeUpdate-> 子updated-> 父updated销毁过程父
beforeDestroy-> 子beforeDestroy-> 子destroyed-> 父destroyed