记录下vue原理中的一些知识点
生命周期
,就是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 -->
<span class="name">{{ name }}</span>
<span class="age">{{ age }}</span>
</div>
</template>