vue生命周期
vue生命周期
个人公众号地址
vue2.x 选项式 API(Options API)
1、前置:
eg:
export default {
name: "DevPoint",
data() {
return { num: "123", };
},
mounted() {}
};
代码的过程:
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
......
vm._self = vm
// 初始化生命周期(找到第一个非抽象父级,将当前实例添加到父实例的 $children 属性里,并设置当前实例的 $parent 为父实例,在当前实例上设置一些属性)
initLifecycle(vm)
// 初始化事件中心(主要调用updateComponentListeners,主要作用就是将绑定在组件上的事件,保存至vm._events属性中)
initEvents(vm)
// 初始化渲染(主要定义了vm的_c和$createElement方法)
initRender(vm)
callHook(vm, 'beforeCreate')
// 初始化注入
initInjections(vm) // resolve injections before data/props
// 初始化状态
// 初始化 props、data、methods、watch、computed 等属性
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
......
}
}
响应式流程:
- 在init的时候会利用Object.defineProperty方法(不兼容 IE8)监听Vue实例的响应式数据的变化从而实现数据劫持能力(利用了 JavaScript 对象的访问器属性get和set,在 Vue3 中会使用 ES6 的Proxy来优化响应式原理)。在初始化流程中的编译阶段,当render function被渲染的时候,会读取Vue实例中和视图相关的响应式数据,此时会触发getter函数进行依赖收集(将观察者Watcher对象存放到当前闭包的订阅者Dep的subs中),此时的数据劫持功能和观察者模式就实现了一个 MVVM 模式中的 Binder,之后就是正常的渲染和更新流程。
- 当数据发生变化或者视图导致的数据发生了变化时,会触发数据劫持的setter函数,setter会通知初始化依赖收集中的Dep中的和视图相应的Watcher,告知需要重新渲染视图,Wather就会再次通过update方法来更新视图。
2、生命周期钩子
生命周期过程 | 组件状态 | 使用场景 |
---|---|---|
new Vue()、New Component Detected() | ||
init Event & Lifecycle | 初始化生命周期、初始化事件中心、初始化渲染 | |
1、beforeCreat() | 实例初始化之后,this 指向创建的实例,不能访问到 data、computed、watch、methods 上的方法和数据。 如果 data() 在这个钩子里面更新,一旦选项式 API(Options API)加载完,更新将会将会丢失数据。 |
它对于调用不操作组件数据的 API 非常有用,常用于初始化非响应式变量。 |
init injections & reactivity 、选项 API 加载 | data 数据注入、 data 数据劫持: (1、递归遍历 data 选项,添加 setter/getter; 2、把劫持过的变量都放在组件实例 this、vm 上) |
|
2、created() | 实例创建完成,可访问 data、computed、watch、methods 上的方法和数据。 未挂载到 DOM,不能访问到$el 属性; $ref 属性内容为空数组 |
常用于简单的 ajax 请求(如果请求信息过多,页面会长时间处于白屏状态),页面的初始、开启 websorcket 长连接化 |
编译模板(如果 App 是用 ' npm run build ' 构建的,这步可能已经完成了) | 1、vue 会判断这个组件有没有 el 挂载点,有就接着判断有没有视图模板 template,如果有,万事大吉,render function 顺利开始; 2、如果没有 el 挂载点,那么得开始创建了; 3、如果没有 template,那就把 el 的 outerHTML 当作 template。 |
|
3、beforeMount() | 模板已编译,因此它存储在内存中,但尚未附加到页面,尚未创建任何 DOM 元素,因此 $el 在这个阶段仍然不可用。 | |
渲染组件(创建 DOM 节点) | 1、根据 render()渲染函数,生成"抽象语法树 AST" ,再把 AST 第一次被创建成“虚拟 DOM(VNode)” (Vnode 是真实 DOM 的一种数据描述,它本质上是 json 格式的数组) 2、根据 Vnode 创建真实 DOM。把声明式变量都替换成真实数据,DOM 渲染完成。| |
|
4、mounted() | 组件已安装并显示在页面上, $el 可被正常使用,在此阶段可以从 Vue 访问和操作 DOM。 | 开定时器、做请求、获取 VNode 信息和操作 |
组件安装——>进入更新阶段 | ||
5、beforeUpdate() | 使用这个钩子来访问 DOM 的当前状态,甚至可以更新 data() 。 | |
更新数据 | 1、当 vue 上下文中的 data 发生变化时,使用 render()渲染函数再生成一个新的 Vnode。 2、使用 Diff 运算,patch('old vnode','new vnode')找出两个 Vnode 之间最小差异。 3、notify 通过 Watcher 根据“依赖收集”再次更新真实 DOM。 【虚拟 DOM 存在的价值:大大地降低了“jQuery 时代下人为寻找 DOM 变化差异”的不足,最小化地去更新 DOM(尽可能地减少了 DOM 操作)。所以虚拟 DOM 是 MVVM 的本质。】 |
|
6、updated() | 访问$el DOM 内容或其他任何有关 DOM 内容的内容,它将显示新的、重新渲染后的版本。 | 大部分时候 watch 选项的功能就满足需求。 避免在这个钩子函数中操作数据,可能陷入死循环 |
组件进入销毁阶段 | 调用$destroy()或路由切换 | |
7、beforeDestory() | 此事件仍然可以访问 DOM 元素以及与组件有关的任何其他内容。 | 1. 清除自己定义的定时器 2. 解除事件绑定 scroll 3. 当前页面使用了$on 需要销毁前解绑 |
组件卸载 | 1、拆卸掉 watcher,所以 DOM 不可能再发生更新。 2、拆卸掉当前组件的所有子组件,所以这些子组件也进入销毁阶段。 3、卸载掉当前组件中的事件处理器。 |
|
8、destroyed() | 仍然可以访问访问 this.$el,以及 data() 、methods 和 watch。 |
3、父子组件生命周期
3.1、加载渲染过程(当子组件完成挂载后,父组件会主动执行一次 beforeUpdate/updated 钩子函数(仅首次))
父 beforeCreate->父 created->父 beforeMount->子 beforeCreate->子 created->子 beforeMount- >子 mounted->父 mounted (首次:->父 beforeUpdate -> 父 updated)
3.2、子组件更新过程
父 beforeUpdate->子 beforeUpdate->子 updated->父 updated
3.3、父组件更新过程
父 beforeUpdate -> 父 updated
3.4、销毁过程
父 beforeDestroy->子 beforeDestroy->子 destroyed->父 destroyed
vue3.x 组合式 API(Composition API)
1、钩子函数的变化
created() 和 beforeCreated() ——> setup()
beforeMount() ——> onBeforeMount()
mounted() ——> onMounted()
beforeUpdate() ——> onBeforeUpdate()
updated() ——> onUpdated()
beforeUnmount() ——> onBeforeUnmount()
unmounted() ——> onUnmounted()
2、用法:在 setup() 函数中定义挂钩
<script>
export default {
setup() {
// 所有钩子逻辑
onBeforeMount(() => {
// beforeMount() 逻辑
});
...
},
};
</script>
或者
<script setup>
// 所有钩子的逻辑代码在这里
</script>