Vue生命周期

78 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

生命周期

简单介绍下生命周期, 生命周期就是每一个Vue实例从创建到卸载的过程,涵盖了从创建实例,初始化数据,编译模板、挂载dom、更新dom、卸载实例等过程。 image.png

初始化阶段

image.png

1. **new Vue() ** 创建Vue实例

2. init event & lifeCycle 初始化事件和生命周期

初始化事件,就是初始化一些绑定事件,比如on,emit等 初始化生命周期的一些状态,比如isMounted,is等,我们熟知的用来创建dom的函数createElement()也在这里初始化。

beforeCreate钩子 参考上下两个周期,我们应该是拿不到el,template,data,methods的

<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.min.js"></script>
  <body>
    <div id="app">
      <p>Hello Vue!</p>
    </div>
  </body>
  <script>
    new Vue({
       el: "#app",
      template: "<div>我是Vue<div>",
      data: {
        msg: "Hello Vue!",
      },
      methods: {
        showMsg: function() {
          console.log(this.msg);
        },
      },
      // init event & lifeCycle 初始化事件和生命周期

      beforeCreate() {
        console.log("template", this.template); // template undefined
        console.log("el", this.el); // el undefined
        console.log("data", this.msg); // data undefined
        this.showMsg(); // TypeError: this.showMsg is not a function
      },
    });
  </script>

3.init injections and reactivity 初始化data、method以及初始化数据劫持以及绑定组件的watcher,以便检测组件数据的变化。

created 在这里仍然拿不到el,template,但是已经能拿到data和methods

 // init injections and reactivity 初始化数据和方法

  created() {
    console.log("template", this.template); // template undefined
    console.log("el", this.el); // el undefined
    console.log("data", this.msg); // data Hello Vue!
    this.showMsg(); // Hello Vue!
   },

编译模板阶段

image.png

这个阶段的目标就是编译模板生成dom保存到内存中,也就是生成了虚拟dom 这里有三个对象都可能作为模板取生成dom: el、template、render函数

el是在页面中已存在的dom节点上选择一个作为Vue的挂载元素; template是在vue中定义的字符串模板,他将会替换挂载元素; render函数是字符串模板的代替模式,依然会替换掉挂载元素;

编译阶段的流程几个重点:

  • 如果不存在el,必须显示调用$mount()才能手动开始编译,否则无法进入到编译阶段;
  • 如果存在el,并且不存在template,render函数,就会使用el编译成template模板,转化成render函数生成虚拟dom;
  • 如果存在el,并且有template, 并且实例中不存在render函数,template会替换el绑定的元素,转化成render函数,通过createElement生成虚拟dom存在内存;
  • 如果三者皆存在,则直接通过render函数生成虚拟dom;
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.min.js"></script>
  <body>
    <div id="app">我是el-{{msg}}</div>
  </body>
  <script>
    new Vue({
      el: "#app",
      data: {
        msg: "Hello Vue!",
      },
      template: "<div>我是template-{{msg}}</div>",
      render: function (createElement) {
        return createElement("div", '我是render-'+this.msg);
      },
      methods: {
        showMsg: function () {
          console.log(this.msg); // Hello Vue!
        },
      },
      // init event & lifeCycle 初始化事件和生命周期

      beforeCreate() {
        console.log("----初始化前----");
        console.log("el:", this.$el); // el undefined
        console.log("data:", this.msg); // data undefined
      },

      // init injections and reactivity 初始化数据和方法

      created() {
        console.log("----初始化后----");
        console.log("el:", this.$el); // el undefined
        console.log("data:", this.msg); // data Hello Vue!
      },

      // 编译阶段

      beforeMount() {
        console.log("----挂载前----");
        console.log("el", this.$el); // el undefined
      },
    });
  </script>

展示一下三者都有的结果。

image.png

beforeMount: 这个钩子刚刚已经用过了,在这里数据的变量占位符还在,还可以在这里最后一次可以修改未渲染前的数据变量。

挂载阶段

1. Create vm.$el and replace "el"  with it

渲染真实dom到页面上,dom中的变量占位符将渲染成真实数据,渲染成功后,真实dom也将替换掉$el原来的值;

 <body>
    <div id="app">
      <p>
        我是el-{{msg}}
      </p>
    </div>
  </body>
  <script>
    new Vue({
      el: "#app",
      data: {
        msg: "Hello Vue!",
      },
      template: "<div>我是template-{{msg}}</div>",
      // render: function (createElement) {
      //   return createElement("div", '我是render-'+this.msg);
      // },
      methods: {
        showMsg: function () {
          console.log(this.msg); // Hello Vue!
        },
      },

      // 编译阶段

      beforeMount() {
        console.log("----挂载前----");
        console.log("el", this.$el); // el undefined
      },
      mounted() {
        console.log("----挂载后----");
        console.log("el", this.$el); // el <div>我是template-Hello Vue!</div>
      }
    });
  </script>

结果可以发现,我们是用template的内容渲染的,可以看到在mounted中,el已经替换成了template的内容。

mounted钩子,在这里页面已经渲染成功,$el被页面上渲染的元素替换,可以通过document去更改数据,触发更新。

image.png

更新阶段

image.png

当我们数据发生改变的时候,会生成一个虚拟dom,然后会用新的虚拟dom和原来的虚拟dom进行diff比较,算出需要修改的范围,然后去更新dom,再通过render去渲染到页面上

beforeUpdate钩子:更新前 数据发生改变后会立刻触发beforeUpdate,生成虚拟dom,所以在这里我们拿到data中的数据已经是改变的,但是这时还没有进行diff和render,所以还没又渲染到页面上。 updated钩子:更新后 数据已经渲染到页面上,这时虚拟dom和页面上的dom都已经更改。

销毁阶段

image.png

beforeDestroy钩子,这时还没有进行销毁,实例的数据,方法都能拿到,在这里我们可以去关闭一些定时器之类的,操作一些实例的函数之类。 destroyed钩子,这时页面已经销毁了,组件的watcher解绑,data、methods、filter以及el都逐个销毁。