生命周期钩子
所有的生命周期钩子自动绑定 this
上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos()
)。这是因为箭头函数绑定了父上下文,因此 this
与你期待的 Vue 实例不同,this.fetchTodos
的行为未定义。
一、创建示例试验钩子函数
<body> <div id="app"> <App></App> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> // 在Test组件中试验钩子函数 var Test = { data(){ return { msg:"啊哈哈" } }, template:` <div> <div>{{msg}}</div> <button @click="changeHandler">修改</button> </div> `, methods:{ changeHandler(){ this.msg = this.msg + 'alex'; } }, beforeCreate(){ // 在当前组件创建之前调用 console.log(this.msg); // 输出undefined,说明当前数据为空 }, created(){ // 在当前组件创建之后调用 // 使用该组件就会触发以上的钩子函数,created中可以操作数据、发送ajax, // 并且可以实现vue对页面的影响,应用主要是:发送Ajax请求 console.log(this.msg); // 控制台输出"啊哈哈" // this.msg="嘿嘿嘿"; }, beforeMount(){ // 装载数据到DOM之前会调用 console.log(document.getElementById('app')); }, mounted(){ // 装载数据到DOM之后会调用 // 这个地方可以操作DOM // 可以获取到真实存在的DOM元素,vue操作以后的DOM console.log(document.getElementById('app')); }, beforeUpdate(){ // 更新之前,调用此钩子,应用:获取原始的DOM console.log(document.getElementById('app').innerHTML); // 获取所有元素 }, updated(){ // 更新之后,调用此钩子,应用:获取最新的DOM console.log(document.getElementById('app').innerHTML); // 获取所有元素 }, beforeDestroy(){ console.log('beforeDestroy'); }, destroyed(){ console.log('destroyed'); }, activated(){ console.log('组件被激活了'); }, deactivated(){ console.log('组件被停用了'); } }; var App = { // 局部组件 data(){ return { isShow:true } }, template:` <div> <keep-alive> <Test v-if="isShow"></Test> </keep-alive> <button @click="changeHandler">改变组件的生死</button> </div> `, methods:{ changeHandler(){ this.isShow = !this.isShow; } }, components:{ // 挂载Test组件 Test } }; // 创建 销毁 new Vue({ el:'#app', template:``, components:{ App } }); </script> </body>
二、各个钩子函数介绍
1、beforeCreate与created
beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created:在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el
属性目前不可见。
template:` <div> {{msg}} </div> `, beforeCreate(){ // 在当前组件创建之前调用 console.log(this.msg); // 输出undefined,说明当前数据为空 }, created(){ // 在当前组件创建之后调用 // 使用该组件就会触发以上的钩子函数,created中可以操作数据、发送ajax, // 并且可以实现vue对页面的影响,应用主要是:发送Ajax请求 console.log(this.msg); // 控制台输出"啊哈哈" this.msg="嘿嘿嘿"; },
显示效果如下所示:
2、beforeMount与mounted
beforeMount:在挂载开始之前被调用:相关的 render
函数首次被调用。该钩子在服务器端渲染期间不被调用。
mounted:el
被新创建的 vm.$el
替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted
被调用时 vm.$el
也在文档内。该钩子在服务器端渲染期间不被调用。
template:` <div> {{msg}} </div> `, beforeMount(){ // 装载数据到DOM之前会调用 console.log(document.getElementById('app')); }, mounted(){ // 装载数据到DOM之后会调用 // 这个地方可以操作DOM // 可以获取到真实存在的DOM元素,vue操作以后的DOM console.log(document.getElementById('app')); },
显示效果如下:
3、beforeUpdate与updated
beforeUpdate:数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。该钩子在服务器端渲染期间不被调用。
var Test = { // 在Test组件中试验钩子函数 data(){ return { msg:"啊哈哈" } }, template:` <div> <div>{{msg}}</div> <button @click="changeHandler">修改</button> </div> `, methods:{ changeHandler(){ this.msg = this.msg + 'alex'; } }, beforeUpdate(){ // 更新之前,调用此钩子,应用:获取原始的DOM console.log(document.getElementById('app').innerHTML); // 获取所有元素 }, updated(){ // 更新之后,调用此钩子,应用:获取最新的DOM console.log(document.getElementById('app').innerHTML); // 获取所有元素 }, };
点击按钮后显示效果如下所示:
第一个是获取了更新之前原始div下面所有dom对象。
第二个是更新之后新div下面所有的dom对象。
4、beforeDestroy与destroyed
beforeDestroy:Vue 实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。
destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
var Test = { // 在Test组件中试验钩子函数 data(){ return { msg:"啊哈哈" } }, template:` <div> <div>{{msg}}</div> <button @click="changeHandler">修改</button> </div> `, methods:{ changeHandler(){ this.msg = this.msg + 'alex'; } }, beforeDestroy(){ console.log('beforeDestroy'); }, destroyed(){ console.log('destroyed'); }, }; var App = { data(){ return { isShow:true } }, template:` <div> <Test v-if="isShow"></Test> <button @click="changeHandler">改变组件的生死</button> </div> `, methods:{ changeHandler(){ this.isShow = !this.isShow; } }, components:{ // 挂载Test组件 Test } };
显示效果如下所示:
点击按钮(改变组件生死)后,将div标签内容删除,显示如下:
组件的销毁和创建是对网页中的DOM是有性能消耗的,一般还是使用下面的激活/停用。
5、activated与deactivated
activated:keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。
deactivated:keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。
var Test = { // 在Test组件中试验钩子函数 data(){ return { msg:"啊哈哈" } }, template:` <div> <div>{{msg}}</div> <button @click="changeHandler">修改</button> </div> `, methods:{ changeHandler(){ this.msg = this.msg + 'alex'; } }, activated(){ console.log('组件被激活了'); }, deactivated(){ console.log('组件被停用了'); } }; var App = { data(){ return { isShow:true } }, template:` <div> <keep-alive> <Test v-if="isShow"></Test> </keep-alive> <button @click="changeHandler">改变组件的生死</button> </div> `, methods:{ changeHandler(){ this.isShow = !this.isShow; } }, components:{ // 挂载Test组件 Test } };
keep-alive组件:用于让当前组件产生缓存。
组件的停用和激活只是和缓存有关,与生命周期没有关系。
点击按钮显示效果如下:
再次点击组件被停用,但dom并不发生修改:
6、errorCaptured
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false
以阻止该错误继续向上传播。
参见:https://cn.vuejs.org/v2/api/#选项-生命周期钩子
三、生命周期图示
组件的停用和激活只是和缓存有关,与生命周期没有关系。