https://segmentfault.com/a/1190000008010666 https://segmentfault.com/a/1190000011381906
https://cn.vuejs.org/v2/guide/instance.html#生命周期图示(图)
beforeCreate:组件实例刚被创建,无属性 created:组件实例创建完成,有属性,没有DOM(el没有被挂载), data已经完成,el生成了,还没有挂载。 beforeMount:模板编译之前,有DOM,并没有把DOM挂载 mounted:模板编译之后,数据都加载到页面上 beforeUpdate:组件更新之前,数据已经更新了,但是没有挂载 updated:组件更新之后,数据已经更新了,并且挂载 activated: keep-alive,组件被激活时 deactivated: keep-alive,组件被激活完成 beforeDestroy:销毁之前,实例仍然完全可用 destroyed:销毁完成,调用后,Vue 实例指示的所有东西都会解绑定, 所有的事件监听器会被移除,所有的子实例也会被销毁 执行了destroy操作,原来样式保留,后续就不再受vue控制了。组件生命周期指的是组件从创建到销毁的过程,在这个过程中的一些不同的阶段,vue 会调用指定的一些组件方法
基本生命周期函数有下面几个阶段:
创建阶段挂载阶段更新阶段卸载阶段每一个阶段都对应着 之前 和 之后 两个函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>{{title}}</h1> <button @click="show=!show">隐藏</button> <hr> <template v-if="hasError"> <h4>有错误发生了</h4> </template> <template v-else> <kkb-component v-if="show" :t="title"></kkb-component> </template> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const kkbComponent = { props: ['t'], template: ` <div> <h1>kkbComponent - {{t.a.b}}</h1> </div> `, beforeCreate() { console.log('kkbComponent:beforeCreate'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, created() { console.log('kkbComponent:created'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, beforeMount() { console.log('kkbComponent:beforeMount'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, mounted() { console.log('kkbComponent:mounted'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, beforeUpdate() { console.log('kkbComponent:beforeUpdate'); console.log('props', this.$props); console.log('='.repeat(100)); }, updated() { console.log('kkbComponent:updated'); console.log('='.repeat(100)); }, beforeDestroy() { console.log('kkbComponent:beforeDestroy'); console.log('this', this); console.log('='.repeat(100)); }, destroyed() { console.log('kkbComponent:destroyed'); console.log('this', this); console.log('='.repeat(100)); } } let app = new Vue({ el: '#app', data: { title: '开课吧', show: true, hasError: false }, components: { 'kkb-component': kkbComponent }, beforeCreate() { console.log('beforeCreate'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, created() { console.log('created'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, beforeMount() { console.log('beforeMount'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, mounted() { console.log('mounted'); console.log('data', this.$data); console.log('el', this.$el); console.log('='.repeat(100)); }, beforeUpdate() { console.log('beforeUpdate'); console.log('props', this.$props); console.log('='.repeat(100)); }, updated() { console.log('updated'); console.log('='.repeat(100)); }, beforeDestroy() { console.log('beforeDestroy'); console.log('this', this); console.log('='.repeat(100)); }, destroyed() { console.log('destroyed'); console.log('this', this); console.log('='.repeat(100)); }, errorCaptured(err, vm, info) { console.log('errorCaptured'); console.log(err, vm, info); console.log('='.repeat(100)); this.hasError = true; return false; } }); </script> </body> </html>初始化阶段,应用不多
在实例创建完成后被立即调用,该阶段完成了对 data 中的数据的 observer,该阶段可以处理一些异步任务
在挂载开始之前被调用,应用不多
该阶段执行完了模板解析,以及挂载。同时组件根组件元素被赋给了 $el 属性,该阶段可以通过 DOM 操作来对组件内部元素进行处理了
数据更新时调用,但是还没有对视图进行重新渲染,这个时候,可以获取视图更新之前的状态
由于数据的变更导致的视图重新渲染,可以通过 DOM 操作来获取视图的最新状态
实例销毁之前调用,移除一些不必要的冗余数据,比如定时器
Vue 实例销毁后调用
当捕获一个来自子孙组件的错误时被调用,此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
如果我们希望获取组件节点,进行 DOM 相关操作,可以通过 ref 和 $refs 来完成
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>{{title}}</h1> <button @click="getBoxHeight">获取 box 的高度</button> <button @click="getKKBComponent">获取自定义组件实例及内部方法</button> <hr> <div ref="box"> 这是内容<br>这是内容<br>这是内容<br>这是内容<br>这是内容<br> </div> <hr> <kkb-component ref="kkb" :t="title"></kkb-component> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const kkbComponent = { props: ['t'], data() { return { isShow: true } }, template: ` <div v-if="isShow"> <h1>kkbComponent - {{t}}</h1> </div> `, methods: { hide() { this.isShow = false; } } } let app = new Vue({ el: '#app', data: { title: '开课吧' }, components: { 'kkb-component': kkbComponent }, mounted() { console.log(this.$refs.kkb); }, methods: { getBoxHeight() { console.log( this.$refs.box.clientHeight ); }, getKKBComponent() { this.$refs.kkb.hide(); } } }); </script> </body> </html>给元素或组件添加 ref 属性,则该元素或组件实例对象将被添加到当前组件实例对象的 $refs 属性下面
该属性的是一个对象,存储了通过 ref 绑定的元素对象或者组件实例对象
当数据更新的时候,视图并不会立即渲染,这个时候我们期望获取到视图更新后的数据,可以通过 nextTick 来进行操作
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <h1>{{title}}</h1> <button @click="setBoxContent">设置新的内容</button> <hr> <div ref="box" style="background: red" v-html="content"></div> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> let app = new Vue({ el: '#app', data: { title: '开课吧', n: 1 }, computed: { content() { return new Array(this.n).fill(this.title).join('<br>'); } }, methods: { setBoxContent() { this.n++; this.$nextTick(_=>{ console.log( this.$refs.box.clientHeight ); }) } } }); </script> </body> </html>nextTick 方法将在更新队列循环结束之后立即调用