Appearance
Vue的生命周期方法
研究方向
- hook机制
研究方法
- 各个hook在哪个阶段触发,为啥会在这个阶段触发?触发这个钩子可以改变什么或者得到什么?
钩子函数(Hook)
钩子是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息; 钩子机制允许应用程序截获处理window消息或特定事件, 钩子函数可以理解为js运行进程中在其特定段时的回调函数
什么是生命周期?
生命周期:Vue 实例从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期,各个阶段有相对应的事件钩子
- 图中 数据观测:
在new Vue() 时 开始观测数据
init event & lifeCycle
: 表示new Vue
后事件和生命周期的init
- 当
created
完成之后,它会去判断instance
(实例)里面是否含有“el”option
(选项),如果没有的话,它会调用vm.$mount(el)
这个方法,然后执行下一步;如果有的话,直接执行下一步。紧接着会判断是否含有“template”
这个选项,如果有的话,它会把template
解析成一个render function
,这是一个template
编译的过程,结果是解析成了render
函数:
render (h) {
return h('div', {}, this.text)
}
render
函数里面的传参h就是Vue里面的createElement
方法,return
返回一个createElement
方法,其中要传3个参数,第一个参数就是创建的div标签;第二个参数传了一个对象,对象里面可以是我们组件上面的props,或者是事件之类的东西;第三个参数就是div标签里面的内容,这里我们指向了data里面的text。
使用render函数的结果和我们之前使用template
解析出来的结果是一样的。render
函数是发生在beforeMount
和mounted
之间的,这也从侧面说明了,在beforeMount
的时候,$el
还只是我们在HTML里面写的节点,然后到mounted
的时候,它就把渲染出来的内容挂载到了DOM
节点上。这中间的过程其实是执行了render function
的内容。
在使用.vue
文件开发的过程当中,我们在里面写了template
模板,在经过了vue-loader
的处理之后,就变成了render function
,最终放到了vue-loader
解析过的文件里面。这样做有什么好处呢?原因是由于在解析template
变成render function
的过程,是一个非常耗时的过程,vue-loader
帮我们处理了这些内容之后,当我们在页面上执行vue
代码的时候,效率会变得更高。
beforeMount
在有了render function
的时候才会执行,当执行完render function
之后,就会调用mounted
这个钩子,在mounted
挂载完毕之后,这个实例就算是走完流程了。 后续的钩子函数执行的过程都是需要外部的触发才会执行。比如说有数据的变化,会调用beforeUpdate
,然后经过Virtual DOM
,最后updated
更新完毕。当组件被销毁的时候,它会调用beforeDestory
,以及destoryed
。
生命周期的钩子 (lifecyclehook)
Vue所有的生命周期钩子自动绑定在this上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法。这是因为箭头函数绑定了父上下文,因此this与你期待的Vue实例不同。
生命周期中的钩子函数 | 组建状态 | 最佳实践 |
---|---|---|
beforeCreate | 实例初始化之后,this指向创建的实例,此时还不能访问到data ,computed ,watch ,methods 上的数据和方法 | 常用于初始化非响应式变量 |
created | 实例创建完成,可以访问到 data ,computed ,watch ,methods 上的数据和方法,未挂载到dom 上,不能访问#el 属性, $ref 属性d额内容为空数组 | 常用语简单的ajax请求 ,页面的初始化 |
beforeMount | 在挂载开始前被调用,beforeMount 之前,会找到对应的template ,并编译成render 函数 | - |
mounted | 实例挂载到DOM上,此时可以通过DOM API 获取到DOM 节点,$ref 属性可以访问 | 常用于获取vnode信息和操作,ajax 请求 |
beforeUpdate | 响应式数据更新时调用,发生在虚拟DOM打补丁之前 | 适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器 |
updated | 虚拟DOM重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作 | 避免在这个钩子函数中操作数据,可能陷入死循环 |
beforeDestroy | 实例销毁之前调用。这一步,实力任然完全可用,this 仍能获取到实例 | 常用于销毁定时器,解绑迁居时间,销毁插件对象等操作 |
destroyed | 实力销毁后调用,调用后,Vue实例只是的所有东西都会解绑,所有的事件监听器会被移除,所有的姿势里也会被销毁 | 在此也可以用于销毁定时器 |
注:
created阶段的
ajax
请求与mounted
请求的区别:前者页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态,此时如果做DOM
请求时会报错,页面还没有渲染出来mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用
vm.$nextTick
(https://blog.csdn.net/sinat_17775997/article/details/71638144)beforeCreate
,created
,beforeMount
,mounted
是自动被调用beforeUpdate
,updated
,beforeDestroy
,destroyed
是手动调用子组件的
created
优先于父组件的created
执行, 父组件的beforeCreate
优先于子组件的beforeCreate
子组件的
mounted
优先于父组件的mounted
, 父组件的beforeMount
优先于子组件的beforeMount
子组件的
destroyed
优先于父组件的beforeDestroy
, 父组件的beforeDestroy
优先于子组件的beforeDestroy
activated & deactivated
最后还有 两个钩子函数没显示:activated & deactivated 使用<keep-alive>
会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务
activated: 在组件被激活时调用,在组件第一次渲染时也会被调用,之后每次keep-alive激活时被调用,该钩子在服务器端渲染期间不被调用。
deactivated: keep-alive组件停用时调用。该钩子在服务端渲染期间不被调用。
组件内的离开当前路由钩子beforeRouteLeave => 路由前置守卫 beforeEach => 全局后置钩子afterEach => deactivated 离开缓存组件 => activated 进入缓存组件(如果你进入的也是缓存路由) // 如果离开的组件没有缓存的话 beforeDestroy会替换deactivated // 如果进入的路由也没有缓存的话 全局后置钩子afterEach=>销毁 destroyed=> beforeCreate等
路由导航守卫
Vue的钩子函数 [路由导航守卫、keep-alive、生命周期钩子]
实例demo: 见template
参考文档:
如何解释vue的生命周期才能令面试官满意?
vue生命周期(五)
深入 Vue 生命周期
Vue 实例中的生命周期钩子详解
Vue.js源码解读
生命周期Vue的钩子函数[路由导航守卫、keep-alive、生命周期钩子]
Vue生命周期中mounted和created的区别
深入理解Vue生命周期、手动挂载及挂载子组件
遗留问题:
兄弟组件通过bus传值时的updated,beforeUpdate 生命周期顺序
如果是通过父级派发更新事件时,beforeUpdate,和updated的顺序 都是自上到下正常顺序进行;
如果是兄弟组件的派发顺序是beforeUpdate是从上到下,updated 的顺序是从下到上的更新顺序beforeCreate 有什么具体实际的用处,例举
vue生命周期中 beforeCreate 是实例初始化完成后数据观测(data observer)和event/watcher之前被调用。在beforeCreate前,所有的options都会先存到vm.$options中,在beforeCreate之后,将$options里的data啦,props啦,methods啦等等一个个附到vm上,然后再触发created钩子。所以在beforeCreate的时候,通过this.message是拿不到值的,在created的时候就能通过this.message拿到值了。
一定要在beforeCreate的时候就同步去拿data里的值的话,就是直接从this.$options.data里去拿。如果data中的初始值是简单的string,那直接this.$options.data()["message"]就好.涉及到复杂点的情况,建议看看源码里是怎么处理的,具体在core/instance/state.js中的initData(vm)里。 还有一种方法 可以使用nextTick(),相当于做个延迟,等页面挂载完后在执行 使用promise
javascriptlet F = null; export default { //... data(){ return { dataList:[] } }, beforeCreate() { F = fetchData(//fetchData是取数方法 //...返回promise ) }, created() { F.then(data=>{ this.dataList = data }) } }
本人理解其中原因就是一个实例初始化后的提示功能,表示此后要开始