【vue2】vue的生命周期以及数据监听分析

版本:vue2.X、ant design vue 1.7.8

1.vue的生命周期是什么?

答:vue的生命周期就是一个组件从创建开始的初始化、挂载、更新等步骤后,最后被卸载的过程;

相当于现实生活中拼图游戏,
先在初始化阶段准备拼图的图板、零散的拼图;
在挂载的阶段把拼图一个一个的拼凑成目标的图案;
在更新阶段相当于把拼图里有部分拼凑错图的扣出来或额外diy新的图放到需要放的地方;
在卸载阶段相当于把拼凑好的拼图欣赏完后再拆散收起来的过程


2.生命周期钩子函数分别有:

挂载阶段
beforeCreate      //数据检测和数据代理的创建之前
created              //数据检测和数据代理的创建创建完毕
beforeMount      //挂载之前
mounted            //挂载完毕
 
更新阶段
beforeUpdate    //更新之前
update              //更新完毕
 
卸载(销毁)阶段
beforeDestroy   //卸载之前
destroyed         //卸载完毕
 
缓存(KeepAlive)阶段
activated           //进入该组件的页面
deactivated       //停用或离开时(但组件并未被销毁)
 
错误提示阶段
errorCaptured   //捕获子孙组件的错误时
errorHandler     //指定组件在渲染和观察期间未捕获错误处理函数

2.1计算属性

computed         //计算属性
watch              //数据监听


3.生命周期执行顺序

按官方文档的示例图解
【vue2】vue的生命周期以及数据监听分析_第1张图片
在页面实践,代码如下
home父页面

<template>
  <div style="padding: 60px">
    <h3 style="color: red">父页面</h3>
    <a-input v-model="message" style="width: 120px"></a-input>
    <div>{{ message }}</div>
    <a-input v-model="test" style="width: 220px"></a-input>
    <a-input v-model="testList" style="width: 220px"></a-input>
    <h3 style="color: red">csdn博主:{{ csdnName }}</h3>

    <a-button @click="showTap">点击卸载</a-button>
    <div>-----------------------------------------</div>
    <div v-if="isHomePageShow">
      <keep-alive>
        <homePage></homePage>
      </keep-alive>
    </div>
    <a-button @click="homePageShowTap">点击隐藏/显示子组件</a-button>
  </div>
</template>

<script>
import homePage from './components/homePage.vue'
export default {
  name: 'Home',
  components: {
    homePage,
  },
  data() {
    return {
      isHomePageShow: true,
      message: 'test',
      isImmediate: '是否开启watch数据监听默认调用',
      test: '监听数据变动调用一个封装方法',
      testList: '监听数据变动调用多个封装方法',
    }
  },
  computed: {
    csdnName() {
      console.group('------computed计算属性状态------')
      const name = '鱼干~'
      console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
      console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
      console.log('%c%s', 'color:red', 'csdn博主: ' + name)
      return name
    },
  },
  watch: {
    message: {
      handler(newVal, oldVal) {
        console.group('------watch数据监听状态------')
        console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
        console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
        console.log('%c%s', 'color:red', '新值: ' + newVal, '旧值: ' + oldVal)
      },
    },
    isImmediate: {
      handler(newVal, oldVal) {
        console.group('------watch数据监听在侦听开始之后立即调用、并且无论其被嵌套多深都可侦听状态------')
        console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
        console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
        console.log('%c%s', 'color:red', '新值: ' + newVal, '旧值: ' + oldVal)
      },
      immediate: true, //该回调将会在侦听开始之后立即调用,默认是false
      deep: true, //该回调将会在被侦听的对象的属性改变时调动,无论其被嵌套多深
    },
    // 字符串方法名称
    test: 'someMethod',
    //监听数据变动调用多个封装方法
    testList: [
      'testListSomeMethod',
      function handler2(newVal, oldVal) {
        console.group('------watch数据监听调用多个封装方法状态------')
        console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
        console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
        console.log('%c%s', 'color:red', '新值: ' + newVal, '旧值: ' + oldVal)
      },
    ],
  },
  beforeCreate: function () {
    console.group('------beforeCreate创建前状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  created: function () {
    console.group('------created创建完毕状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //已被初始化
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message) //已被初始化
  },
  beforeMount: function () {
    console.group('------beforeMount挂载前状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //已被初始化
    console.log('%c%s', 'color:red', 'message: ' + this.message) //已被初始化
  },
  mounted: function () {
    console.group('------mounted 挂载结束状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //已被初始化
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //已被初始化
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message) //已被初始化
  },
  beforeUpdate: function () {
    console.group('beforeUpdate 更新前状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  updated: function () {
    console.group('updated 更新完成状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  beforeDestroy: function () {
    console.group('beforeDestroy 销毁前状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  destroyed: function () {
    console.group('destroyed 销毁完成状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  errorCaptured(err, vm, info) {
    console.group('errorCaptured 捕获子孙组件的错误阶段===============》')
    console.log(`错误返回: ${err.toString()}\n在哪个钩子发生的错误: ${info}\nvue实例: ${vm}`)
  },
  methods: {
    testListSomeMethod() {
      console.log('通过watch调用该testListSomeMethod方法')
    },
    someMethod() {
      console.log('通过watch调用该someMethod方法')
    },
    homePageShowTap() {
      this.isHomePageShow = !this.isHomePageShow
    },
    showTap() {
      this.$destroy('home')
    },
  },
}
</script>

homePage子页面

<template>
  <div>
    <h3 style="color: red">子页面</h3>
    <div>{{ message }}</div>
  </div>
</template>

<script>
export default {
  name: 'HomePage',
  data() {
    return {
      message: '这里是子组件homePage',
    }
  },
  beforeCreate: function () {
    console.group('------子组件beforeCreate创建前状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  created: function () {
    messageTest = '制造错误触发errorCaptured'
    console.group('------子组件created创建完毕状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //已被初始化
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message) //已被初始化
  },
  beforeMount: function () {
    console.group('------子组件beforeMount挂载前状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //已被初始化
    console.log('%c%s', 'color:red', 'message: ' + this.message) //已被初始化
  },
  mounted: function () {
    console.group('------子组件mounted 挂载结束状态------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //已被初始化
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //已被初始化
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message) //已被初始化
  },
  beforeUpdate: function () {
    console.group('子组件beforeUpdate 更新前状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  updated: function () {
    console.group('子组件updated 更新完成状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  beforeDestroy: function () {
    console.group('子组件beforeDestroy 销毁前状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  destroyed: function () {
    console.group('子组件destroyed 销毁完成状态===============》')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el)
    console.dir(this.$el)
    console.log('%c%s', 'color:red', 'data   : ' + this.$data)
    console.dir(this.$data)
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  activated() {
    console.group('------activated缓存阶段,进入组件------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
  deactivated() {
    console.group('------activated缓存阶段,离开或停用当前组件------')
    console.log('%c%s', 'color:red', 'el     : ' + this.$el) //undefined
    console.log('%c%s', 'color:red', 'data   : ' + this.$data) //undefined
    console.log('%c%s', 'color:red', 'message: ' + this.message)
  },
}
</script>

<style  scoped>
</style>

控制台的截图,打印顺序如下:【vue2】vue的生命周期以及数据监听分析_第2张图片

首先是beforeCreate创建之前,当前组件实例还未创建,通过用于创建开发初始化任务

再是watch数据监听,当前watch设置了immediate为true,该回调将会在侦听开始之后立即调用,默认是false

再是created创建完毕,在这个状态中我们的el,也就是Dom元素依旧是拿不到的,但是我们已经可以拿到data了,这意味着 created已经将数据加载进来了 ,通常这里用于发送异步数据请求

再是beforeMount挂载之前,DOM节点未创建,未执行渲染、更新,所以在这之前el还是拿不到

再是computed 计算属性,可为函数或对象{{get,set}},一般函数即可;不会书写set,适合一个值受多个数据影响,一般会返回结果;具备缓存属性,多次在模板中使用只会计算一次;


//如果有子级组件
再是子组件beforeCreate
再是子组件create
再是子组件errorCaptured捕获子孙组件的错误时,提示了子组件哪里有问题
再是子组件beforeMount
再是子组件beforeMount
再是子组件activated


最后是mounted挂载完毕,DOM节点创建完成,通常可以使用$refs$el来获取DOM节点,所以此阶段可以拿到el了。我们可以用console.dir去打印一些我们需要的元素的属性。

然后在更新阶段,在vue页面有如下代码

 <a-input v-model="message" style="width: 120px"></a-input>
 <div>{{ message }}</div>
  <h3 style="color: red">csdn博主:{{ csdnName }}</h3>

【vue2】vue的生命周期以及数据监听分析_第3张图片
然后我们在input输入框输入更改message数据,截图如下
【vue2】vue的生命周期以及数据监听分析_第4张图片


//如果有计算属性watch
则会进入watch数据监听状态,可为函数或对象{{handler,immediate,deep}};默认初始化不会执行,除非将immediate设置为true;适合一个值影响多个数据,执行多个操作,可不返回任何结果;适合执行异步或开销比较大的操作


每当我们去改变页面元素的时候,就会进入更新阶段,也就是beforeUpdate,updated这两个状态。
beforeUpdate是更新前,通常用于获取更新前的各种状态
update是更新后,所有状态都是最新的


如果有子组件,则进行进入、离开(停用)子组件顺序
【vue2】vue的生命周期以及数据监听分析_第5张图片
当点击隐藏/显示子组件按钮
【vue2】vue的生命周期以及数据监听分析_第6张图片
先是进入父级组件beforeUpdate
再是进入子组件activated
再是进入子组件beforeDestroy
再是进入子组件destroyed
再是进入父级组件activated


然后在卸载(销毁)阶段,在vue父级新有下代码

//在template代码块增加如下按钮
  <a-button @click="showtap">点击卸载</a-button>
 //在script增加一个方法
  methods: {
    showtap() {
      this.$destroy('home')
    },
  },

点击卸载按钮后截图如下:【vue2】vue的生命周期以及数据监听分析_第7张图片

beforeDestroy销毁前状态,在销毁前元素、data都是可以打印出来的,通常用于定时器或取消订阅等,此时组件实例仍然存在


//如果有子组件
则进入activated
再是子组件beforeDestroy 销毁前状态
再是子组件destroyed 销毁完成状态


destroyed销毁完成的状态也是什么都可以打印出来,组件已销毁,此时组件实例不存在

beforeDestroydestroyed,都是我们离开这个组件才会被调用的生命周期。

4.总结

生命周期:

又名:生命周期回调函数、生命周期函数、生命周期钩子。
是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
生命周期函数中的this指向是vm 或 组件实例对象。
 
常用的生命周期钩子:

mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
 
关于销毁Vue实例
销毁后借助Vue开发者工具看不到任何信息。
销毁后自定义事件会失效,但原生DOM事件依然有效。
一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
 
官网:https://cn.vuejs.org/api/options-lifecycle.html#beforecreate

【vue2】vue的生命周期以及数据监听分析_第8张图片

你可能感兴趣的:(vue.js,前端,javascript)