# Vue2教程 - 12 生命周期函数

生命周期函数也就是组件从创建到销毁的过程中,触发的回调方法,我们可以在回调方法中进行一些操作。

通过学习组件的生命周期函数,我们可以知道在哪个生命周期函数中可以发起网络请求来获取数据,在哪个生命周期函数中才可以获取到组件中的数据,哪个生命周期函数中可以操作DOM。

# 12.1 生命周期

下图展示了Vue对象实例的生命周期。(来自官网)

下面解释一下:

# 1 new Vue()

表示开始创建一个Vue的实例对象;

# 2 初始化事件&生命周期函数

表示刚初始化了一个Vue空的实例对象,这个时候这个对象上只有默认的一些默认的事件和生命周期函数,其他的东西都未创建。

注意:在 beforeCreate 生命周期函数执行的时候,datamethods 中的数据都还没有被初始化。

<!-- 在使用独立安装方式使用vue.js,使用过这样的方式 -->
<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'ok'
        },
        methods: {
            show() {
                console.log('执行了show方法')
            }
        },
        beforeCreate() { // 这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行它
            // console.log(this.msg)
            // this.show()
            // 注意: 在 beforeCreate 生命周期函数执行的时候,data 和 methods 中的 数据都还没有没初始化
        }
    });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3 初始化注入&校验

在这一步会初始化 Vue 对象中的 datamethods 等属性,所以在后面的 created 生命周期函数中,datamethods 已经被初始化好了。

所以如果想调用 methods 中的方法或操作 data 中的数据,最早只能在 created 函数中操作。

<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'ok'
        },
        methods: {
            show() {
                console.log('执行了show方法')
            }
        },
        beforeCreate() {},
        created() { // 这是遇到的第二个生命周期函数
            // console.log(this.msg)
            // this.show()
            // 在 created中,data 和 methods 都已经被初始化好了!
            // 如果要调用methods中的方法,或者操作data中的数据,最早只能在created中操作
        }
    });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 4 是否指定el选项

查看Vue对象是否有el属性。

# 5 是否指定templete选项

查看Vue对象是否有template属性

# 6 将template编译到render函数中

# 7 将el“内”部的HTML作为template编译

将el指定的元素内部的html作为模板进行编译。

上面的四步主要是进行模板编译,将Vue代码中的那些指令进行执行,最终在内存中生成一个编译好的最终模板字符串,然后把这个模板字符串渲染为内存中的DOM,此时只是在内存中渲染好了模板,并没有把模板挂载到真正的页面中去。

接下来回执行 beforeMount 生命周期函数,这个时候页面模板已经加载到内存中了,尚未挂载到页面中,页面中的元素还是模板字符串,不是真正显示的内容。

<div id="app">
    <input type="button" value="修改msg" @click="msg='No'">
    <h3 id="h3">{{msg}}</h3>
</div>


<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'ok'
        },
        methods: {
            show() {
                console.log('执行了show方法')
            }
        },
        beforeCreate() {},
        created() {},
        beforeMount() { // 这是遇到的第3个生命周期函数,表示模板已经在内存中编辑完成了,但是尚未把模板渲染到页面中
            console.log(document.getElementById('h3').innerText);  //打印内容:{{msg}}
            // 在beforeMount执行的时候,页面中的元素还没有被真正替换过来,只是之前写的一些模板字符串
        }
    });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 8 创建vm.$el并用其替换el

这一步将内存中编译好的模板正式替换到浏览器页面中去,然后会执行 mounted 生命周期函数。

<div id="app">
    <input type="button" value="修改msg" @click="msg='No'">
    <h3 id="h3">{{ msg }}</h3>
</div>


<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'ok'
        },
        methods: {
            show() {
                console.log('执行了show方法')
            }
        },
        beforeCreate() {},
        created() {},
        beforeMount() {},
        mounted() { // 这是遇到的第4个生命周期函数,表示内存中的模板已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了
            console.log(document.getElementById('h3').innerText);   //打印内容:ok
            // 注意: mounted 是实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,此时,如果没有其它操作的话,这个实例就静静的躺在我们的内存中,一动不动
        }
    });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

如果想要通过某些插件操作页面上的DOM节点,最早要在 mounted 中进行。

只要执行了 mounted,就表示整个Vue实例已经初始化完成了,此时组件已经脱离了创建阶段,进入到了运行阶段。

# 9 挂载完毕

此时组件已经被挂载到页面。

当每次data被修改时,都会调用 beforeUpdate 生命周期方法,这时data中的数据已经更新了,但是界面还没有渲染。

<div id="app">
    <input type="button" value="修改msg" @click="msg='No'">
    <h3 id="h3">{{msg}}</h3>
</div>

<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'ok'
        },
        methods: {
            show() {
                console.log('执行了show方法')
            }
        },
        beforeCreate() {},
        created() {},
        beforeMount() {},
        mounted() {},
        // 接下来的是运行中的两个事件
        beforeUpdate() { // 这时候,表示我们的界面还没有被更新,数据已经被更新了
//当点击修改msg按钮时,data数据被修改了,回调了beforeUpdate生命周期方法
            console.log('界面上元素的内容:' + document.getElementById('h3').innerText);
            console.log('data中的msg数据是:' + this.msg)
            // 得出结论:当执行beforeUpdate的时候,页面中的显示的数据还是旧的,此时data数据是最新的,页面尚未和最新的数据保持同步
        }
    });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 10 虚拟DOM重新渲染并应用更新

先根据data中最新的数据,在内存中重新渲染出一份最新的内存DOM树,当最新的内存DOM树被更新之后,会把最新的内存DOM树重新渲染到页面中去,这时候就完成了从 data(Model层)-> view(视图层)的更新。

页面重新渲染完成,会执行 updated 生命周期函数,这个时候页面和 data 数据已经保持了同步了,都是最新的。

<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'ok'
        },
        methods: {
            show() {
                console.log('执行了show方法')
            }
        },
        beforeCreate() {},
        created() {},
        beforeMount() {},
        mounted() {},
        beforeUpdate() {},
        updated() {
            console.log('界面上元素的内容:' + document.getElementById('h3').innerText)
            console.log('data 中的 msg 数据是:' + this.msg)
            // updated 事件执行的时候,页面和 data 数据已经保持同步了,都是最新的
        }
    });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 11 解除绑定销毁子组件及事件监听

当执行 beforeDestroy 生命周期函数的时候,Vue实例就已经从运行阶段,进入到了销毁阶段;

当执行 beforeDestroy 的时候,实例身上所有的 data 和所有的 methods 以及过滤器、指令都处于可用状态,此时还没有真正执行销毁的过程。

# 12 销毁完毕

当执行到 destroyed 函数的时候,组件已经被完全销毁了,此时组件中所有的数据,方法、过滤器、指令等都已经不可用了。

# 12.2 总结生命周期函数

组件的生命周期可以分为四个阶段:

# 1 创建

  • beforeCreate:此时组件的datamethods等属性均不存在,即无法访问到组件的属性和方法。
  • created:在实例创建完成后被立即调用。在这一步,可以调用 methods 中的方法和 data 中的数据,但无法访问到DOM元素。发送网络请求从后端服务器获取数据,建议放在这个函数中发起。

# 2 挂载

  • beforeMount:在挂载开始之前被调用,此时组件的模板已经编译完成,但尚未挂载到DOM树中,页面还是Vue的占位符。
  • mounted此时组件已经成功地挂载到DOM树中,可以进行DOM操作

# 3 更新

  • beforeUpdate:由于数据更改导致虚拟DOM重新渲染之前调用。
  • updated:组件发生更新,重新渲染之后会调用该函数,此时组件 DOM 已经更新,需要注意,要避免在此期间更改数据,因为这可能会导致无限循环。

# 4 销毁

  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。适合在此进行清理任务,比如清除定时器、解绑全局事件等。
  • destroyed:Vue 实例销毁后调用,调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。可用于完成销毁之后的收尾工作。