组件生命周期——组件内钩子

组件生命周期( 组件内钩子 )

生命周期

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

  1. 组件的有哪几个阶段?
  • 初始化阶段
  • 运行中阶段
  • 销毁阶段

. 初始化阶段

  • 分为两个大阶段, 每一个大阶段包含两个生命周期钩子函数 ---- 生命周期 --》人的一生 钩子函数 --》 (人在某个阶段做得一些事情, 这些事情是自动触发)
  • 有那四个钩子函数呢?每个钩子函数有什么功能?项目中有什么用呢?
. beforeCreate (在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。)
  • 表示组件创建前的准备工作, 为事件的发布订阅 和 生命周期的开始做初始化
  • 这个钩子函数中
  • 数据拿不到, 真实DOM也拿不到
  • 这个钩子在项目中我们没有什么实际用途
. created (实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。)
  • 表示组件创建结束
  • 这个钩子函数中
  • 数据拿到了, 但是真实DOM没有拿到
  • 这个钩子函数在项目
  • 数据请求, 然后可以进行一次默认数据的修改
. beforeMount (在挂载开始之前被调用:相关的 render 函数首次被调用)
  • 表示组件装载前的准备工作
  • 判断 el选项有没有, 判断 template选项有没有 , 如果没有, 那么需要手动装载
  • 如果有,那么通过render函数进行模板的渲染(没有做的,正要进行, VDOM)
  • 这个钩子函数中
  • 数据拿到了, 真实DOM没有拿到
  • 这个钩子函数在项目中,
  • 数据请求, 它也可以进行一次数据修改
. mounted (el 被新创建的 vm. e l r o o t m o u n t e d v m . el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm. el 也在文档内。)
  • 表示组件装载结束, 就是我们可以在视图中看到了
  • 这个钩子函数中
  • 数据拿到了, 真实DOM也拿到了
  • 这个钩子函数在项目:
  • DOM操作就可以进行了, 第三方库的实例化
  • 总结: 由上对比,我们可以知道, 数据请求越提前越好一些, created常用于数据的请求和数据的修改, 第三方库的实例化常在mounted中进行书写

代码示例

<body>
  <div id="app">
    <life-circle></life-circle>
  </div>
  <template id="life-circle">
    <div>
      <h3> 组件生命周期的 初始化阶段 </h3>
      <p> {{ msg }} </p>
    </div>
  </template>
</body>
<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>

. 运行中阶段

- 运行中阶段一共有两个钩子函数

beforeupdate (数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。)
  • 表示数据更新前的准备工作
  • 这个钩子不主动执行,当数据修改了, 才会执行
  • 这个钩子函数中
  • 数据拿到了, 并且拿到的是修改后的数据
  • DOM也输出了
  • 这个钩子函数更多的工作内容为:生成新的 VDOM , 然后通过diff算法进行两次VDOM 对比
  • 这个钩子在项目中
  • 因为他主要做的事情是内部进行的, 所以对我们而言没有太多的操作意义
updated (由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。)
  • 表示数据更新结束, 通过render函数渲染真实DOM
  • 这个钩子函数的执行也是, 当数据修改的时候才执行
  • 这个钩子函数中
  • 数据拿到了, DOM也拿到了
  • 这个钩子在项目中
  • 也是进行第三方库的实例化( DOM是改变的 )
  • 总结: 数据更新, 也要进行DOM操作那么, 我们使用update这个钩子

代码示例

<body>
  <div id="app">
    <life-circle></life-circle>
  </div>
  <template id="life-circle">
    <div>
      <h3> 运行中阶段 </h3>
      <p> {{ msg }} </p>
    </div>
  </template>
</body>
<script>
  Vue.component('LifeCircle',{
    template: '#life-circle',
    data () {
      return {
        msg: 'hello vue.js'
      }
    },
    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'
  })
</script>

. 销毁阶段

  • 用过开关销毁
  • 这个组件真实DOM也会被删除掉
  • 通过调用vm.$destroy()
  • 这个组件的被删除了, 但是它的真实DOM的html结构还在
  • 包含两个钩子函数
beforeDestroy(实例销毁之前调用。在这一步,实例仍然完全可用)
destroyed(Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。)
  • 这两个钩子无差别
  • 这两个钩子在项目中
  • 做善后工作 , 手动清除一些计时器, 和一些方法, 还有第三方实例化出来的对象
  • 我们建议大家使用开关的形式来操作组件的销毁和创建

代码示例

<body>
  <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>
</body>
<script>
  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
    }
  })
</script>

. 用案例来写一个生命周期 第三方库的实例化来做 swiper

真实DOM存在了, 才能实例化

  1. 直接写死了
  • DOM就没有渲染
  • 数据直接有了
  1. 数据请求
  • 我们常规是往 updated 钩子里面写, 但是遇到问题了?
  • 问题是: 当我们有其他数据更新时,updated钩子就会重复触发, 也就是说第三方库要重复实例化
  • 解决:
  1. 在updated钩子中添加判断条件, if(!this.swiper){}
  2. 在数据请求里面写, 但是发现无法获得真实DOM
  3. 将实例化代码发到异步队列
  • setTimeout(function(){},0) 将实例化代码发到这里面 [不推荐]
  • Vue.nextTick() /this.$nextTick 优先使用
  • 概念: nextTick表示DOM渲染之后执行的业务

组件内钩子具体使用方法代码

<body>
    <p id="container">
        <p>{{msg}}</p>
        <!--点击的时候isShow进行取反 -->
        <button @click="isShow = !isShow">切换是否显示组件</button>
        <my-component v-if="isShow"></my-component>
    </p>
    <script>
        Vue.component("my-component", {
            template: `
     <p>
     <button @click="handleClick">Click Me</button>
     <h1>component:{{count}}</h1>
     </p>
`,
            data: function() {
                return {
                    count: 0
                }
            },
            methods: {
                handleClick: function() {
                    this.count++;
                }
            },
            beforeCreate: function() {
                console.log('准备创建组件');
            },
            created: function() {
                console.log('组件创建完毕');
            },
            beforeMount: function() {
                console.log('组件的模板准备挂载到DOM');
            },
            mounted: function() {
                console.log('挂载完毕');
            },
            beforeUpdate: function() {
                console.log('准备更新了');
            },
            updated: function() {
                console.log('更新完成');
            },
            beforeDestroy: function() {
                console.log('准备destroy');
            },
            destroyed: function() {
                console.log('destroy完成');
            }
        })
        new Vue({
            el: "#container",
            data: {
                msg: "Hello VueJs",
                isShow: true
            }
        })
    </script>
</body>
</html>

生命周期练习,需要哪阶段写哪个阶段

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>生命周期练习</title>
<script src="js/vue.js"></script>
</head>
<body>
<p id="container">
<p>{{msg}}</p>
<my-component></my-component>
</p>
<script>
Vue.component("my-component",{
data:function(){
    return {
     myOpacity:0
    }
},
template:` <h1 v-bind:style="{opacity:myOpacity}">透明度将改变
</h1>`,
mounted:function(){
    setInterval(function(){
     this.myOpacity += 0.1;
     if(this.myOpacity>1){
     this.myOpacity = 0;
     }
    }.bind(this),1000)
}
})
new Vue({
el:"#container",
data:{
    msg:"Hello VueJs"
}
})
</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/xuwei1215225/article/details/89496997