组件的生命周期
- 什么是组件的生命周期?
当前组件在创建到销毁经历的一系列过程叫做组件的生命周期 - 组件有哪几个阶段
- 初始化阶段
- 运行中阶段
- 销毁阶段
生命周期三部曲(组件的三个阶段)
一、初始化阶段 :有4个钩子函数,触发条件是自动的
钩子函数:就是option配置项中的一个方法,在特定的触发条件(时机)下会自动触发
-
beforeCreat
(1)组件即将创建,进行组件事件和生命周期的初始化;
(2)这个钩子函数中,数据获取不到,真实DOM也拿不到
(3)这个阶段是一个事件和生命周期的准备阶段,也是必不可少的,
(4)在项目中没有什么实际用途 -
created
(1)组件创建完成
(2)这个钩子函数中,获取到了数据,但是没有拿到真实DOM
(3)如果同步的去更改数据,运行中的钩子函数不会执行
(4)在项目中可进行:
1)数据的修改
2)异步数据请求
3)初始化事件的绑定 -
beforeMount
(1)组件即将挂载
(2)判断根实例组件是否有el选项,判断组件是否有template选项,如果没有,那么需要手动挂载;如果有,那么通过render函数进行模板的渲染(还没有渲染,正要进行,VDOM)
(3)这个钩子函数中,获取到了数据,但是真实的DOM没有拿到
(4)在项目中可进行:
1)异步请求接口数据
2)数据修改 -
mounted
(1)组件挂载结束,可以在视图中看到
(2)这个钩子函数中,数据拿到了,真实DOM也渲染出来了
(3)可以进行DOM操作,第三方库的实例化
二、 运行中阶段:有2个钩子函数,触发条件:数据挂载完毕且当data选项中的数据发生改变时触发
-
beforeUpdata
(1)表示数据更新前的准备工作
(2)在这个钩子函数中:
1)数据拿到了,并且拿到的是修改后的数据
2)拿到了真实DOM
(3) 这个钩子函数更多的工作内容:生成新的VDOM,然后通过diff算法进行两次VDOM对比
(4)在项目中,因为这个钩子函数主要做的事情是内部进行的,所以对我们而言没有太多的操作意义 -
updated
(1)组件更新结束,通过render函数将VDOM渲染成真实DOM,然后驱动vue进行视图更新
(2)这个钩子函数中,数据拿到了,真实DOM也拿到了
(3)在项目中
1)进行第三方库的实例化(DOM是改变的)
三、 销毁阶段:有2个钩子函数
- beforeDestroy
组件即将销毁。在这一步,实例仍然完全可用。 - destroyed
Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑,所有的事件监听器会被移除,所有的子实例也会被销毁。 - 销毁的两种方式
(1)调用vm.$destroy()方法(内部销毁)
缺点:这个组件被删除了,但是它的真实DOM的html结构还在
(2)使用开关销毁——v-if(外部销毁)
这个组件真实DOM也会被删除掉- 这两个钩子函数在项目中,做善后工作,手动清除一些计时器和一些方法,还有第三方实例化出来的对象
生命周期案例——第三方库的实例化来做swiper
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./base/swiper.min.css">
</head>
<body>
<div id="app">
<my-banner></my-banner>
</div>
<!--创建模板-->
<template id="my-banner">
<div class="swiper-container">
<div class="swiper-wrapper">
<div
class="swiper-slide"
v-for="banner in banners"
>
<img width="100%" :src="banner.image" alt="">
</div>
</div>
</div>
</template>
<!-- 需要引入的js资源 -->
<script src="./base/swiper.min.js"></script>
<script src="./base/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-resource/1.5.0/vue-resource.min.js"></script>
<script>
//创建组件
Vue.component("my-banner",{
template:"#my-banner",
data(){//这里的data必须是函数,因为组件的数据是独立的,有一定的作用域
return {
banners:[]
}//返回一个对象值,为了符合数据驱动原理设计,让observer将data选项中的数据设置
},
created(){
this.$http.get("./banners.json").then(res=>{
//console.log(res.data.bannerList)
this.banners = res.data.bannerList
//实例化Swiper
// new Swiper(".swiper-container",{
// loop:true
// })
/*
运行之后发现了个问题,轮播图是可以滚动的,但是划不过去
原因是因为在这里实例化的时候,最外层的swiper-container容器是存在的,也就是页面当中这个真实dom是存在的。
而我们进行异步请求的swiper-slide这四个真实dom是不存在的,当数据刚刚更改完,内部会生成新的虚拟dom,然后
新的虚拟dom与旧的虚拟dom结构会进行对比,比较出来差异后才会更新真实dom的swiper-slide的dom结构。
而虚拟dom之间的对比是有时间的,而更改完数据后立即进行实例化操作,等虚拟dom更新完毕后生成真实的dom结构,
其实实例化操作已经提前结束了。
*/
})
},
//beforeMount()这个钩子函数解决不了上述问题!因为这个钩子函数只获取得到数据,但是拿不到真实dom的结构。
// beforeMount(){
// new Swiper(".swiper-container",{
// loop:true
// })
// }
//mounted这个钩子函数也解决不了上述问题!因为上面是异步的过程,它不会阻止后续mounted的相关操作。
//内部的异步请求去进行请求数据的同时,下面的mounted钩子函数也正在执行,当数据回来进行进行更改操作,其实这个实例化操作早就结束了。
// mounted(){
// new Swiper(".swiper-container",{
// loop:true
// })
// }
//beforeUpdate这个钩子函数也解决不了上述问题!
//当dom挂载完毕,数据发生改变的时候,这个钩子函数就会立即执行!
// beforeUpdate(){
// new Swiper(".swiper-container",{
// loop:true
// })
// }
//最后发现updated这个钩子函数可以解决上述问题
//当数据发生改变的时候,虚拟dom就会进行对比,虚拟dom对比完成后,再去渲染真实的dom结构
//当真实的dom结构渲染完成后,内部才会执行updated钩子函数
//也就是说,数据改变了,然后swiper-slide这几个真实dom生成好了之后,才会进入到updated这个钩子函数里面去。
updated(){
new Swiper(".swiper-container",{
loop:true
})
}
})
new Vue({
el:"#app"
})
</script>
</body>
</html>