生命周期钩子
这篇文章主要记录与生命周期相关的问题。 之前,我们讲到过生命周期,如下所示:
根据图示我们很容易理解vue的生命周期:
- js执行到new Vue() 后,即进入vue的beforeCreate状态。
- 接着观察data下的数据,紧接着create。
- create之后,就会检测是否含有el属性,如果有,就直接检测是否含有模板属性; 如果没有,就当vm.$mount()调用之后再检测,vm.$mount()的作用就是将Vue实例挂载到某一个DOM元素上。
- 如果有template,那么我们就编译模板到render函数中,作用就是为了将模板中的元素渲染进去;如果没有template,我们就把el所在的HTML作为模板编译。
- 这样就进入了 beforeMount 状态。
- 在mounted 之前,就会创建一个 vm.$el 用来替代 实例中的el, ok! 这样就可以mouted了。
- 接着,如果data发生了变化,就会有beforeUpdata,在替换了之后,就是updated的状态啦! 这是一个循环的过程,因为updated是可以一直更新的嘛!
- 最后如果我们调用了 vm.$destroy() 就会进入 beforeDestory, 然后解除 watchers、child components 以及 listeners,最后就destroyed了, 那么他的生命也就结束了。
总结来说: 是 new Vue() 开启了vue实例的生命周期, vm.$destroy() 结束了vue实例的生命周期。
当然了,对于不同的生命周期,都对应着相应的钩子函数,且一共有8个钩子函数,如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="example"> <p>朱振伟</p> {{message}} </div> <script> var example=new Vue({ el:'#example', beforeCreate () { alert("beforeCreate"); }, created () { alert("created"); }, beforeMount () { alert("beforeMount"); }, mounted () { alert("mounted"); }, beforeUpdate () { alert("beforeUpdate"); }, updated () { alert("updated"); }, beforeDestroy () { alert("beforeDestroy"); }, destroyed () { alert("destroyed"); } }); </script> </body> </html>
当我们运行之后,会发现,beforeCreate、created、beforeMount、mounted以此触发,如果我们在控制台输入 example.message = "JohnZhu"; 那么就又会依次触发 beforeUpdate 和 updated 对应的钩子函数, 如果我们在控制台输入 example.$destroy() 那么就会依次触发 beforeDestroy 和 destroyed 对应的钩子函数。
生命周期大概就是这样了。
补充:
除了在vue官网(上图)中提到的生命周期钩子之后,vue2中还添加了 activated 和 deactivated 钩子函数,当渲染的组件启用了 keep-alive 时,那么进入一个路由指定的组件时,就会调用 activated 钩子函数,如果一个组件没有设定 keep-alive ,那么就不会调用 activated 钩子函数, 而是调用 deactivated 钩子函数。
比如:
<div id="app"> <keep-alive> <router-view></router-view> </keep-alive> </div>
这里的 router-view 是所有的页面都会在这里渲染的,而 keep-alive 又包裹在这之外,所以说这个app中的所有路由在切换时都会调用 activated 钩子函数。
单文件组件下的生命周期
先看下面这个例子:
<template> <div class="personal-wrap"> <Personal></Personal> <button v-on:click="exit" class="btn" v-if="loginBool">退出登录</button> <button v-on:click="login" class="btn btn-login" v-else>现在登录</button> <FooterMenu></FooterMenu> </div> </template> <script> import FooterMenu from '@components/menu'; import Personal from '@components/personal'; import {mapState,mapMutations, mapActions} from 'vuex' export default { components: { FooterMenu, Personal }, data () { return { loginBool: Boolean(sessionStorage.getItem("loginBool")) } }, methods: { ...mapMutations([ 'UPDATE_PICTURES' ]), ...mapActions([ 'loginWx' ]), exit: function () { var result = confirm("确认注销登录?"); if (result == true) { window.location.href = window.location.href.replace(window.location.search, ""); } }, login: function () { this.loginWx(2); } }, beforeCreate () { document.title = "替换之后"; }, created () { this.UPDATE_PICTURES(3); alert( 'created' + JSON.stringify(document.querySelector('.btn'))); }, beforeMount () { alert( 'beforeMounte' + JSON.stringify(document.querySelector('.btn'))); }, mounted () { alert( 'mounted' + JSON.stringify(document.querySelector('.btn'))); } } </script>
这是一个单文件组件,因为只是为了说明生命周期的使用,删去了一部分。
- beforeCreate 是在创建data之前的钩子,即这时刚刚创建完Vue实例,然后el,data这些还都没有,但是因为这是单文件组件,所以,document.title是可以访问到的,这点值得注意。并且由于这时候是没有data和method可以使用的,所以不能使用method下的方法。
- 接着在created之后,el仍然是没有挂载的,但是data已经初始化完成了,并且一些方法(methods)也已经可以使用了,没有挂载,所以访问不到单组件中的html元素。
- boforeMount 这时仍然没有挂载,只是开始调用了render函数,同样,没有挂载,也是访问不到vue单组件中的html元素的。
-
在mounted之后, 这时已经将vue和组件联系起来,挂载完成,所以就可以得到其中的html元素了。
常用的钩子
可以看出,我们可以在beforeCreate中使用一些操作document的方法。 在created中可以使用大部分的方法。 在 mounted中可以使用与挂载元素相关的一些方法,如操作dom。
补充: 当然,因为localStorage这种东西都是一直存在的,所以在任何生命周期下都是可以正常访问 localStorage 和 sessionStorage的。