Vue组件生命周期
一个组件从创建到销毁的过程叫做生命周期,其实每个人都要经历一个从出生到死亡的过程,每个阶段都有需要自己要做的事情;组件也一样,在生命周期的每个阶段也有它自己应该做的事情,所以生命周期也理解透彻,在以后的项目中的每一个效果,都是从生命周期中做的。
每个Vue实例在被创建时,需要设置数据监听、编译模板、将实例挂载在DOM元素上并实时更新DOM元素,以数据推动视图,同时在这个过程也会运用到生命周期的函数,在生命周期中给自己添加代码的机会。
首先,先来一张官网上的图:
可以看到在vue一整个的生命周期中会有很多钩子函数提供给我们在vue生命周期不同的时刻进行操作, 那么我们来一一详解:
1、首先先来说下 beforeCreate() 钩子函数:
beforeCreate(创建前)
当组件初始化的时候会执行 beforeCreate ,在当前生命周期中,我们是无法访问到data中的属性,以及methods中的方法和其他生命周期方法;
因为当前生命周期是初始化阶段,因此可以在当前生命周期中加一个loading,等待组件加载完毕以后再移除loading;
var vm=new Vue({
data:{
msg:10,
},
methods:{
handler(){
},
},
beforeCreate(){
//this 指向 vm实例
console.log(this.handler) // underfined
console.log(this.msg) //underfined
},
})
2、与 beforeCreate()钩子函数相对应的还有 created() 钩子函数:
created()(创建后)
当前生命周期可以访问到data中的属性以及methods中的方法;
当前生命周期执行的时候会将data身上的所有属性遍历添加getter/setter方法;
当前生命周期执行的时候会将data与methods身上所有的属性和方法遍历到vm的实例身上;
因为当前生命周期会遍历data身上的属性添加getter/setter,因此可以在当前生命周期函数中进行前后端数据的交互;
var vm=new Vue({
el:"#app",
data:{
msg:10,
},
methods:{
handler(){
},
},
created(){
console.log(this.msg) //10
console.log(this.handler) //显示hadnler这个函数
},
})
按照生命周期整个流程接下来会判断是否有 el 的配置项,如果没有的情况下可以挂载一个,有的话就继续往下走,会再次判断是否有 template 的配置项,有 template 的配置项 会走编译函数,然后用 render 这个函数去渲染,没有的话就走NO(outerHTML)这个模板,我们现在以上面代码为例,所以走outerHTML:
3、下面的生命周期是 beforeMount()钩子函数:
beforeMount()(挂载前)
当前生命周期是数据和模板还未进行结合,可以在当前生命周期中做数据最后的更改;
<body> <div id="app"> <h2>{{msg}}</h2> </div> <script> var vm=new Vue({
el:"#app", data:{ msg:10, }, methods:{ handler(){ } }, beforeMount(){ //在Vue中尽量不用DOM节点,这样会耗费性能,Vue本身就是数据驱动的 console.log(document.getElementById("#app").innerHTML) // <h2>{{msg}}</h2> 会打印出这个模板 当前数据和模板还未相结合 this.msg=100 //在当前生命周期函数做了更改,在下边的生命周期函数做了做后的渲染 }, mounted(){ }, }) </script> </body>
4、接下来就是 mounted()钩子函数:
mounted()(挂载后)
当前生命周期是数据和模板进行相结合,可以在当前生命周期中获取到真实的DOM结构;
之前说不可以操作DOM结构,在这里我们可以通过虚拟DOM元素去做操作,Vue中提供了一个方法叫做 ref ,通过给元素添加 ref 属性,然后在 mounted()中通过 this.$refs. 属性即可获取。
我们可以在当前生命周期中做方法的实例化,例如(swiper、echarts...)
<body> <div id="app"> <h2 ref="h2">{{msg}}</h2> <!--ref属性里边的h2可以是其他值--> </div> <script> var vm=new Vue({
el:"#app", data:{ msg:10, }, methods:{ handler(){ } }, beforeMount(){ console.log(document.getElementById("#app").innerHTML); // <h2>{{msg}}</h2> 这个是模板 this.msg="100"; }, mounted(){ console.log(document.getElementById("#app").innerHTML) ; // <h2>100</h2> 这个是真实的DOM结构
console.log(this.$refs.h2) }, }) </script> </body>
5、当数据更新的时候先会执行 beforeUpdate ():
beforeUpdate( ) (更新前)
在当前生命周期是更新数据与模板还未进行结合,可以在当前生命周期中做数据更改;
<body> <div id="app"> <h2 >{{msg}}</h2> <button @click="updateHandler">更新</button> </div> <script> var vm=new Vue({
el:"#app", data:{ msg:10, }, methods:{ updateHandler(){ this.msg=100; } }, beforeUpdate(){ //按理来说应该是100,但点击更新后最后输出的值为200; this.msg="200"; }
})
</script>
</body>
6、数据更新后会后执行 updated ( ) :
updated()(更新后)
更新后的数据与模板进行相结合,在当前生命周期中我们可以获取到数据更新后最新的DOM结构;
注意:beforeUpdate 与 updated 这两个生命周期会多次执行,因此在这两个周期中做逻辑操作的时候要加条件处理,否则会极度浪费性能。
<body> <div id="app"> <h2 ref="h2">{{msg}}</h2> <!--ref属性里边的h2可以是其他值--> </div> <script> var vm=new Vue({
el:"#app", data:{ msg:10, }, methods:{ handler(){ } }, beforeMount(){ console.log(document.getElementById("#app").innerHTML); // <h2>{{msg}}</h2> 这个是模板 this.msg="100"; }, mounted(){ console.log(document.getElementById("#app").innerHTML) ; // <h2>100</h2> 这个是真实的DOM结构 console.log(this.$refs.h2) }, updated(){ console.log(this.$refs.h2) //也可以从这个方式获取到真实的DOM结构 //做一个条件处理 if(!this.swiper){ this.swiper= new Swiper() } }, }) </script> </body>
7、还有就是 beforeDestroy():
beforeDestroy(销毁前):
在当前生命周期中仍然可以获取到真实的DOM结果,因此我们可以在当前做事件的移除、事件的解绑等;
如果说我们在mounted中做了事件侦听,当组件被销毁时,我们要做一个移除;
8、最后一个是 destroyed():
destroy()(销毁后)
在当前生命周期中我们访问不到真实的DOM结构,以及当前的vm实例化与页面之间的关联也断开了;
<body> <div id="app"> <h2 >{{msg}}</h2> <button onclick="destroyHandler()">更新</button> </div> <script> var vm=new Vue({
el:"#app", data:{ msg:10, }, methods:{ updateHandler(){ this.msg=100; } }, destroyed(){ console.log(this.$refs.h2) //获取不到真实的DOM结构 } }) function destroyHandler(){ vm.$destroy() } </script> </body>
9、当我们每次刷新页面或者跳转页面的时候,都需要请求数据,这样极大的浪费性能,不利于页面的优化,这时候我们就需要使用组件 keep-alive , 来提升性能的优化,
被 keep-alive 包裹的组件第一次被创建后就会保存在内存当中,不会被经历销毁,下次页面切换时就会从缓存中读取。
<keep-alive> <router-view></router-view> </keep-alive> <!-- 只要把要缓存的代码包裹在keep-alive中就可以了 -->
只要被keep-alive包裹的组件就会增加两个生命周期:A、activated 活跃状态 B、deactivated 缓存状态
A、activated 钩子函数
把需要调转的页面代码在 activated 中就可以实现跳转
activated () {
console.log("activated调用了");
}