Vue组件的生命周期

组件生命周期

钩子函数,就是options里面的key, 它的值是函数
钩子函数写在其他配置项的后面

  1. 组件的有哪几个阶段?
    • 初始化阶段
    • 运行中阶段
    • 销毁阶段
  2. 初始化阶段
    • 分为两个大阶段, 每一个大阶段包含两个生命周期钩子函数 ---- 生命周期 --》人的一生 钩子函数 --》 (人在某个阶段做得一些事情, 这些事情是自动触发)
    • 有那四个钩子函数呢?每个钩子函数有什么功能嗯?项目中有什么用呢?
      1. beforeCreate
        • 表示组件创建前的准备工作, 为事件的发布订阅 和 生命周期的开始做初始化
        • 这个钩子函数中
          • 数据拿不到, 真实DOM也拿不到
        • 这个钩子在项目中我们没有什么实际用途
      2. created
        • 表示组件创建结束
        • 这个钩子函数中
          • 数据拿到了, 但是真实DOM没有拿到
        • 这个钩子函数在项目
          • 数据请求, 然后可以进行一次默认数据的修改
      3. beforeMounte
        • 表示组件装载前的准备工作
          • 判断 el选项有没有, 判断 template选项有没有 , 如果没有, 那么需要手动装载
          • 如果有,那么通过render函数进行模板的渲染(没有做的,正要进行, VDOM)
        • 这个钩子函数中
          • 数据拿到了, 真实DOM没有拿到
        • 这个钩子函数在项目中,
          • 数据请求, 它也可以进行一次数据修改
      4. mounted
        • 表示组件装载结束, 就是我们可以在视图中看到了
        • 这个钩子函数中
          • 数据拿到了, 真实DOM也拿到了
        • 这个钩子函数在项目:
          • DOM操作就可以进行了, 第三方库的实例化
            5.案例:
        	  <div id="app">
        <life-circle></life-circle>
      </div>
      <template id="life-circle">
        <div>
          <h3> 组件生命周期的 初始化阶段 </h3>
          <p> {{ msg }} </p>
        </div>
      </template>
      
      <script>
      Vue.component('LifeCircle',{
        template: '#life-circle',
        data () {
          return {
            msg: 'hello vue.js'
          }
        },
        // 初始化阶段钩子函数
        beforeCreate () { //表示组件创建前的准备工作( 初始化事件和生命周期 )     ----  小孩降生前的准备工作
          /* 
            组件未创建, 所以没有this , 数据拿不到 , DOM也拿不到
          */
          console.log('01-beforeCreate');
          console.log( 'data',this.msg )
          console.log( 'DOM',document.querySelector('p'))
          /*       axios({
                  url: './data.json'
                })
                  .then( res => {
                    this.msg = res 
                  })
                  .catch( error => console.log(error))
          */
        },
        created () { // 组件创建结束
          console.log('02-created')
          console.log( 'data',this.msg )
          console.log( 'DOM',document.querySelector('p'))
       /*    axios({
            url: './data.json'
          })
            .then( res => {
              this.msg = res 
            })
            .catch( error => console.log(error)) */
          
        },
        beforeMount () { 
          console.log( '03-beforeMounte' )
          console.log( 'data',this.msg )
          console.log( 'DOM',document.querySelector('p'))
      /*       axios({
            url: './data.json'
          })
            .then( res => {
              this.msg = res 
            })
            .catch( error => console.log(error)) */
        },
        mounted () {
          console.log('04-mounted')
          console.log('data',this.msg)
          console.log('Real DOM',document.querySelector('p'))
          axios({
            url: './data.json'
          })
            .then( res => {
              this.msg = res 
            })
            .catch( error => console.log(error))
        }
      })
      new Vue({
       
      }).$mount('#app')
      </script>
      
  • 总结: 由上对比,我们可以知道, 数据请求越提前越好一些, created常用于数据的请求和数据的修改, 第三方库的实例化常在mounted中进行书写
  1. 运行中阶段
    • 运行中阶段一共有两个钩子函数
      • beforeupdate
        • 表示数据更新前的准备工作
        • 这个钩子不主动执行,当数据修改了, 才会执行
        • 这个钩子函数中
          • 数据拿到了, 并且拿到的是修改后的数据
          • DOM也输出了
        • 这个钩子函数更多的工作内容为:生成新的 VDOM , 然后通过diff算法进行两次VDOM 对比
        • 这个钩子在项目中
          • 因为他主要做的事情是内部进行的, 所以对我们而言没有太多的操作意义
      • updated
        • 表示数据更新结束, 通过render函数渲染真实DOM
        • 这个钩子函数的执行也是, 当数据修改的时候才执行
        • 这个钩子函数中
          • 数据拿到了, DOM也拿到了
        • 这个钩子在项目中
          • 也是进行第三方库的实例化( DOM是改变的 )
          • 案例:
          • 		<!-- html代码 --!>
            				<div id="app">
                <life-circle></life-circle>
              </div>
              <template id="life-circle">
                <div>
                  <h3> 运行中阶段 </h3>
                  <p> {{ msg }} </p>
                </div>
              </template>
            
 			//JS代码
 			 Vue.component('LifeCircle',{
 template: '#life-circle',
 data () {
   return {
     msg: 'hello'
   }
 },
 beforeUpdate () {     
   console.log( 'beforeUpdate' )
   console.log( 'data', this.msg)
   console.log( 'DOM', document.querySelector('p') )
 },
 updated () {
   console.log( 'updated' )
   console.log( 'data', this.msg )
   console.log( 'DOM' , document.querySelector('p') )
   // document.querySelector('p').style.background = 'red'
 }
})
new Vue({
 el: '#app'
})

- 总结: 数据更新, 也要进行DOM操作那么, 我们使用update这个钩子
  1. 销毁阶段
    • 用过开关销毁
      • 这个组件真实DOM也会被删除掉
    • 通过调用vm.$destroy()
      • 这个组件的被删除了, 但是它的真实DOM的html结构还在
    • 包含两个钩子函数
      • beforeDestroy
      • destroyed
      • 这两个钩子无差别
      • 这两个钩子在项目中
        • 做善后工作 , 手动清除一些计时器, 和一些方法, 还有第三方实例化出来的对象
    • 我们建议大家使用开关的形式来操作组件的销毁和创建
      案例:
   <!-- html代码 --!>
   	<div id="app">
       <button @click = 'flag = !flag'> 销毁 </button>
       <life-circle v-if = "flag"></life-circle>
     </div>
     <template id="life-circle">
       <div>
         <h3> 销毁阶段 </h3>
         <button @click = 'destroy'> 销毁 </button>
       </div>
     </template>
Vue.component('LifeCircle',{
 template: '#life-circle',
 methods: {
   destroy(){
     this.$destroy()
   }
 },
 created () {
   this.timer = setInterval( () => {
     console.log('1')
   },1000)
 },
 beforeDestroy () {
   console.log('beforeDestory')
 },
 destroyed () {
   console.log('destroyed')
   clearInterval( this.timer )
   // 如果是用$destroy这个方法来清除组件, 那么我们必须手动清除这个组件的外壳
   document.querySelector('#app div').remove()
 }
})
new Vue({
 el: '#app',
 data: {
   flag: true
 }
}) 
  1. 用案例来写一个生命周期 第三方库的实例化来做 swiper
<!-- 需要引入的资源 --!>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.0/css/swiper.min.css">
   <script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.0/js/swiper.min.js"></script>
   <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
   <script src="../vue.js/vue.js"></script>
   <style>
   .swiper-container {
   width: 600px;
   height: 300px;
} 
   </style>
 <div id="app">
     <my-swiper></my-swiper>
 </div>
 <template id="my-swiper">
         <div class="swiper-container">
                 <div class="swiper-wrapper">
                     <div class="swiper-slide" v-for="item in swiper">
                         <img :src="item.src" alt="">
                     </div>
                     
                 </div>
                 <!-- 如果需要分页器 -->
                 <div class="swiper-pagination"></div>
                 
                 <!-- 如果需要导航按钮 -->
                 <div class="swiper-button-prev"></div>
                 <div class="swiper-button-next"></div>
                 
                 <!-- 如果需要滚动条 -->
                 <div class="swiper-scrollbar"></div>
             </div>
             <!-- 导航等组件可以放在container之外 -->
 </template>   
<script>
    Vue.component("MySwiper",{
        template:"#my-swiper",
        data () {
            return {
                swiper :[
                {
                "id": 1,
                "src": "https://m.360buyimg.com/babel/jfs/t1/38920/7/978/98861/5cbb35f6E9289f045/9372bac08d061fdc.jpg"
                },
                {
                "id": 2,
                "src": "https://img1.360buyimg.com/da/jfs/t1/36709/25/3628/65612/5cb9417bE5b30fdff/5cf6415bc396c9d0.jpg"
                },
                {
                "id": 3,
                "src": "https://m.360buyimg.com/babel/jfs/t1/38920/7/978/98861/5cbb35f6E9289f045/9372bac08d061fdc.jpg"
                }
            ]
            } 
        },
        beforeCreate () {

        },
        created () {
          
        },
        beforeMount () {
            
        },
        mounted () {
        //      this.mySwiper = new Swiper ('.swiper-container', {
        //     loop: true, // 循环模式选项
        //     // 如果需要前进后退按钮
        //     navigation: {
        //     nextEl: '.swiper-button-next',
        //     prevEl: '.swiper-button-prev',
        //     },
        // })   
        },
        beforeUpdate () {

        },
        updated () {
        
            this.mySwiper = new Swiper ('.swiper-container', {
            loop: true, // 循环模式选项
            // 如果需要前进后退按钮
            navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev',
            },
        })  
        },
        beforeDestroy () {

        },
        destroyed () {

        }
    })
    new Vue({
        el:"#app"
    })
</script>
     DOM就没有渲染
     数据直接有了
     上面这个案例直接写死了数据,导致数据没有更新,所以卸载update钩子里的函数不会执行
  1. 真实DOM存在了, 才能实例化,所以要是直接写在create中必须要使用异步操作

  2. 数据请求
    • 我们常规是往 updated 钩子里面写, 但是遇到问题了?
    • 问题是: 当我们有其他数据更新时,updated钩子就会重复触发, 也就是说第三方库要重复实例化
      <!-- html代码 --!>
    
      		<div id="app">
          <my-swiper></my-swiper>
      </div>
      
      <template id="my-swiper">
              <div class="swiper-container">
                      <div class="swiper-wrapper">
                          <div class="swiper-slide" v-for="item in swiper">
                              <img :src="item.src" alt="">
                          </div>
                          
                      </div>
                      <!-- 如果需要分页器 -->
                      <div class="swiper-pagination"></div>
                      
                      <!-- 如果需要导航按钮 -->
                      <div class="swiper-button-prev"></div>
                      <div class="swiper-button-next"></div>
                      
                      <!-- 如果需要滚动条 -->
                      <div class="swiper-scrollbar"></div>
                  </div>
                  <!-- 导航等组件可以放在container之外 -->
      </template>   
    
		<script>
		    Vue.component("MySwiper",{
		        template:"#my-swiper",
		        data () {
		            return {
		                swiper : null
		            } 
		        },
		        beforeCreate () {
		
		        },
		        created () {
		          axios({
		              url:"./swiper.json"
		          })
		          .then ( ( res ) => {
		              this.swiper  = res.data
		          } )
		          .catch ( ( error ) => {
		              if( error ){
		                throw error
		              }
		          } )
		        },
		        beforeMount () {
		            
		        },
		        mounted () {
		       
		        },
		        beforeUpdate () {
		
		        },
		        updated () {
		            this.mySwiper = new Swiper ('.swiper-container', {
		            loop: true, // 循环模式选项
		            // 如果需要前进后退按钮
		            navigation: {
		            nextEl: '.swiper-button-next',
		            prevEl: '.swiper-button-prev',
		            },
		        })  
		        },
		        beforeDestroy () {
		
		        },
		        destroyed () {
		
		        }
		    })
		    new Vue({
		        el:"#app"
		    })
		</script>
    - 解决: 
        1. 在updated钩子中添加判断条件, ` if(!this.swiper){} `  
updated () {
          if( !this.mySwiper ){
              this.mySwiper = new Swiper ('.swiper-container', {
          loop: true, // 循环模式选项
          // 如果需要前进后退按钮
          navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev',
          },
      })  
          }
      },
        3. 在数据请求里面写, 但是发现无法获得真实DOM
              1. 将实例化代码发到异步队列
                 - setTimeout(function(){},0) 将实例化代码发到这里面    [不推荐]
                 - 案例:
                    created () {
        axios({
            url:"./swiper.json"
        })
        .then ( ( res ) => {
            this.swiper  = res.data
        } )
        .catch ( ( error ) => {
            if( error ){
              throw error
            }
        } )

        setTimeout( function () {
          this.mySwiper = new Swiper ('.swiper-container', {
          loop: true, // 循环模式选项
          // 如果需要前进后退按钮
          navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev',
          },
      })  
        },0)
      },
                 - Vue.nextTick() /this.$nextTick      优先使用
                     - 概念: nextTick表示DOM渲染之后执行的业务
 created () {
        axios({
            url:"./swiper.json"
        })
        .then ( ( res ) => {
            this.swiper  = res.data;
            Vue.nextTick((  ) => {
          this.mySwiper = new Swiper ('.swiper-container', {
          loop: true, // 循环模式选项
          // 如果需要前进后退按钮
          navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev',
          },
      })  
  })
        } )
        .catch ( ( error ) => {
            if( error ){
              throw error
            }
        } )
      }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值