vue生命周期&父子组件钩子函数调用顺序

121 阅读1分钟

生命周期各阶段状态

总结:注意注释部分内容,各个阶段可以访问的属性

<!DOCTYPE html>
<html>
    <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">
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
           
        </style>    
    </head>
    <body>
        <div id="app">
           <label>生日</label>
           <input type="date" v-model="birthday"/>
            <div>当前用户{{getAge}}周岁了</div>
            <custom-el v-if="show">
                <span>测试测试测试</span>
            </custom-el>
        </div>
        <script>
            //监听全局异常
           Vue.config.errorHandler = function (err, vm, info) {
                console.log(err)
            }
            //自定义元素,用于测试销毁元素生命周期
            Vue.component("custom-el",{
                data:function(){
                    return {
                        msg:'dddddddd'
                     }
                },
                created:function(){
                    //抛出错误,验证 异常捕获钩子
                    throw new Error("测试异常捕获钩子")
                },
                template:`
                   <div>
                   <span>{{msg}}</span>
                   <slot></slot></div>
                `
            })
          
            var app = new Vue({
                el:"#app",
                data:function(){
                    return {
                        birthday:'2010-10-10',
                        show:true
                    }
                },
                beforeCreate:function(){
                    //创建之前,无法拿到 $data 与 $el
                    console.log("beforeCreate")
                    console.log(this.birthday)
                    console.log(this.$el)
                },
                created:function(){
                    //创建之前,只能拿到$data ,但无法拿到$el
                    console.log("created")
                    console.log(this.birthday)
                    console.log(this.$el)
                },
                beforeMount:function(){
                    //挂载之前,可以拿到$data与$el,但是$el是未解析的虚拟dom
                    console.log("beforeMount")
                    console.log(this.birthday)
                    console.log(this.$el)
                },
                mounted:function(){
                    console.log(this)
                    //挂载之后,可以拿到$data与$el,此时$el为已被解析的真实dom
                    console.log("beforeMount")
                    console.log(this.birthday)
                    console.log(this.$el)
                },
                beforeUpdate:function(){
                    //在$data已经修改,但是组件dom并未更新渲染时调用
                    console.log("beforeUpdate")
                    console.log(JSON.stringify(this.$data))//新的数据
                    console.log(this.$el.innerHTML)//原始dom
                },
                updated:function(){
                    //在$data已经修改,组件dom已被重新渲染之后调用
                    console.log("updated")
                    console.log(JSON.stringify(this.$data))//新的数据
                    console.log(this.$el.innerHTML)//新的dom,不能保证所有子组件被重新渲染
                    this.$nextTick(function(){
                        console.log(this.$el.innerHTML)//新的dom,可以保证所有子组件被重新渲染了
                    })
                },
                //此处存在问题,并未验证出来beforeDestroy与destroyed的区别
                beforeDestroy:function(){
                    //实例销毁之前被调用,这一步,实例仍然完全可用
                    console.log("beforeDestroy")
                    this.birthday = '2014-11-11'
                },
                destroyed:function(){
                    //Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,
                    //所有的事件监听器会被移除,所有的子实例也会被销毁。
                    console.log("destroyed")
                },
                errorCaptured:function(err,vm,info){
                    //当捕获一个来自子孙组件的错误时被调用
                    console.error(err)
                    //如果返回false,则会阻止错误继续向上传播,否则会被全局errorHandler捕获
                    return true;
                },
                methods:{
                   
                },
                computed:{
                  getAge:function(){
                      if(this.birthday){
                        let date = new Date();
                        let birth = new Date(this.birthday)
                        let m1 = date.getMonth()
                        let m2 = birth.getMonth()
                        let et = m1>m2?0:1
                        if(m1==m2 && data.getDate() > birth.getDate()){
                            et = 0;
                        }
                        return date.getFullYear() - birth.getFullYear() - et
                      }
                      return 0;
                  }
                },
                filters:{
                   
                }
            })
        </script>
    </body>
</html>

生命周期钩子函数执行顺序

结论

  • 组件挂载维度:beforeMount、render、mounted
  • 数据更新维度:beforeUpdate、render、updated
var vm = new Vue({
  data: {
    message: '111'
  },
  beforeMount() {
    console.log("beforeMount");
  },
  mounted() {
    console.log("mounted");
  },
  beforeUpdate() {
    console.log("beforeUpdate");
  },
  updated() {
    console.log("updated");
  },
  render(){
  	console.log("render");
  }
})

父子组件嵌套钩子函数调用顺序

// father.vue示例代码

<script>
import son from './son.vue'
export default {
  data () {
    return {
      fmsg: '我是父组件模板'
    }
  },
  beforeCreate () {
    console.log('father-beforeCreate');
  },
  created () {
    console.log('father-created');
  },

  beforeMount () {
    console.log('father-beforeMount');
  },
  mounted () {
    console.log('father-mounted');
  },
  beforeUpdate () {
    console.log('father-beforeUpdate');
  },

  updated () {
    console.log('father-updated');
  },

  beforeDestroy () {
    console.log('father-beforeDestroy');
  },
  destroyed () {
    console.log('father-destroyed');
  },
  methods: {
    fatherClick () {
      this.fmsg = 'ffffff'
    },
  },
  render () {
    console.log('father-render');
    return (
      <div>
        <div class="father" onClick={this.fatherClick}>{this.fmsg}</div>
        <son />
      </div>
    )
  }
}
</script>
// son.vue
<script>
export default {
  data () {
    return {
      smsg: '我是子组件模板'
    }
  },
  beforeCreate () {
    console.log('son-beforeCreate');
  },
  created () {
    console.log('son-created');
  },

  beforeMount () {
    console.log('son-beforeMount');
  },
  mounted () {
    console.log('son-mounted');
  },
  beforeUpdate () {
    console.log('son-beforeUpdate');
  },

  updated () {
    console.log('son-updated');
  },

  beforeDestroy () {
    console.log('son-beforeDestroy');
  },
  destroyed () {
    console.log('son-destroyed');
  },
  methods: {
    sonClick () {
      this.smsg = 'sssssss'
    },
  },
  render () {
    console.log('son-render');
    return (
      <div class="son" onClick={this.sonClick}>{this.smsg}</div>
    )
  }
}
</script>
// main.js
import Vue from "vue";
import father from './components/testFatherAndSonInvokeOrder/father.vue'
new Vue({
  data () {
    return {
    }
  },
  components: {
    father
  },
  render () {
    return <father />
  }
}).$mount("#app");

参考

juejin.cn/post/684490…