Vue生命周期以及父子组件加载顺序
初始化 - beforeCreate & created
beforeCreate
:初始化 vue 实例。data
methods
等尚未被初始化,无法调用。
created
:vue 实例初始化完成,完成响应式绑定。data
methods
等都已初始化完成,可调用。尚未开始渲染模板。
注意:beforeCreate & created
并没有渲染 DOM,不能够访问 DOM。如果组件在加载的时候需要和后端有交互,如果是需要访问 props
、data
等数据的话,就需要使用 created
钩子函数。
/**
*
* vue2.6.X源码地址src/core/instance/init.js
* beforeCreate 和 created 函数都是在实例化 Vue 的阶段,在 _init 方法中执行的。
*
**/
Vue.prototype._init = function (options?: Object) {
vm._self = vm
initLifecycle(vm) // 初始化生命周期相关的属性、相关属性赋值
initEvents(vm) // 初始化事件队列以及监听器
// 通过defineProperty的set去notify()通知subscribers有值被修改,并执行watchers的update函数
// attrs/$listeners的响应化
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm) // initState 的作用是初始化 props、data、methods、watch、computed 等属性
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
}
beforeCreate() {
this.$data // undefined
this.$el // undefined
this.$computed // undefined
this.$methods // undefined
}
created() {
this.$data // {__ob__: Observer}
this.$el // undefined
this.$computed // 可以访问到计算属性
this.$methods // 可以访问到methods中的方法
}
挂载 - beforeMount & mounted
beforeMount
:编译模板,调用 render
函数生成虚拟 V-Dom 。但还没有开始渲染真实Dom。
mounted
:完成DOM渲染 。组件创建完成。开始由创建阶段进入运行阶段。
/**
*
* vue2.6.X源码地址src/core/instance/lifecycle.js
* beforeMount 钩子函数发生在 mount,也就是 DOM 挂载之前,它的调用时机是在 mountComponent 函数中
*
**/
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
vm.$el = el
// ...
callHook(vm, 'beforeMount')
let updateComponent
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
updateComponent = () => {
const name = vm._name
const id = vm._uid
const startTag = `vue-perf-start:${id}`
const endTag = `vue-perf-end:${id}`
mark(startTag)
const vnode = vm._render()
mark(endTag)
measure(`vue ${name} render`, startTag, endTag)
mark(startTag)
vm._update(vnode, hydrating)
mark(endTag)
measure(`vue ${name} patch`, startTag, endTag)
}
} else {
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
}
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
hydrating = false
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
return vm
}
// 在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数。
beforeMount{
this.$data // {__ob__: Observer}
this.$el // undefined
this.$computed // 可以访问到计算属性
this.$methods // 可以访问到methods中的方法
}
// 实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问。
mounted() {
this.$data // {__ob__: Observer}
this.$el // <div id="app"></div>
this.$computed // 可以访问到计算属性
this.$methods // 可以访问到methods中的方法
}
更新 - beforeUpdate & updated
/**
*
* vue2.6.X源码地址src/core/observer/scheduler.js
* update 的执行时机是在flushSchedulerQueue 函数调用的时候
*
**/
beforeUpdate
Vue具有响应式原理,即能够监测到数据的变化。当视图层的数据即将被更新前,就会触发这个生命周期,这个阶段主要可以用在得知哪个组件即将发生数据改动,并且可以移除对其绑定的事件监听器。
updated
此阶段已经重新渲染完成数据更新后的状态。
注意,尽量不要在 updated
中继续修改数据,否则可能会触发死循环。如果要更改官方建议使用computed
或watch
来进行数据更改。
销毁 - beforeDestroy & destroyed - vue2.0版本
beforeDestroy
当组件销毁前会进行的操作,卸载组件实例后调用。实例仍然是完全正常的。移除、解绑一些全局事件、自定义事件,可以在此时操作。
destroyed
组件被销毁。子组件也已销毁。但是父组件已经渲染在 DOM 上的视图仍然会保留在页面上,只有子组件会完全消失。
销毁 - beforeDestroy & destroyed - vue3.0版本
beforeUnmount
当组件销毁前会进行的操作,卸载组件实例后调用。实例仍然是完全正常的。移除、解绑一些全局事件、自定义事件,可以在此时操作。
unmounted
组件被销毁。子组件也已销毁。但是父组件已经渲染在 DOM 上的视图仍然会保留在页面上,只有子组件会完全消失。
特殊钩子函数 - activated、deactivated - keep-alive组件
activated:被 keep-alive
缓存的组件激活时调用。
deactivated:被 keep-alive
缓存的组件停用时调用。
如何正确的操作 DOM
mounted
和 updated
都不会保证所有子组件都挂载完成。如果想等待所有视图都渲染完成,需要使用 $nextTick
。
mounted() {
this.$nextTick(function () {
// 仅在整个视图都被渲染之后才会运行的代码
})
}
VUE3.0 Composition API 生命周期有何不同
setup
代替了beforeCreate
和created
。- 生命周期换成了函数的形式,如
mounted
->onMounted
。文档 。
import { onUpdated, onMounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('mounted')
})
onUpdated(() => {
console.log('updated')
})
}
}
Axios等请求数据请求放在哪个生命周期合适?
一般有两个选择:created
和 mounted
,建议选择后者 mounted
。
执行速度
- 从理论上来说,放在
created
确实会快一些 - 但 ajax 是网络请求,其时间是主要的影响因素。从
created
到mounted
是 JS 执行,速度非常快。 - 所以,两者在执行速度上不会有肉眼可见的差距
代码的阅读和理解
- 放在
created
却会带来一些沟通和理解成本,从代码的执行上来看,它会一边执行组件渲染,一边触发网络请求,并行 - 放在
mounted
就是等待 DOM 渲染完成再执行网络请求,串行,好理解。
所以,综合来看,更建议选择 mounted
。
Vue父子组件的执行顺序
加载渲染时
父组件 beforeCreate
父组件 beforeCreate
父组件 created
父组件 beforeMount
子组件 beforeCreate
子组件 created
子组件 beforeMount
子组件 mounted
父组件 mounted
更新时
父组件 beforeUpdate
子组件 beforeUpdate
子组件 updated
父组件 updated
销毁时
父组件 beforeDestroy
子组件 beforeDestroy
子组件 destroyed
父组件 destoryed
参考链接
Vue.js 生命周期 https://ustbhuangyi.github.io/vue-analysis/v2/components/lifecycle.html#beforeupdate-updated
Vue源码解析 https://blog.csdn.net/qq_46299172/article/details/107657663?spm=1001.2014.3001.5502
Vue生命周期及父子组件生命周期的加载顺序 https://www.cnblogs.com/yyy0926/p/15654272.html