使用Vue开发已经有一段时间了。但发现自己对vue的理解还是不深刻。于是想着从观看Vue文档开始。在阅读文档之前,觉得需要先了解整个Vue的生命周期,清楚的认识到Vue在每个阶段的钩子函数没这样才能更好的让我们去使用Vue。
我们先来看一张图,上面解释每个步骤是做什么的。可以只看这一张图就可以明白Vue实例的整个流程。
 
每个Vue实例在被创建之前都要经历过一系列的初始化过程,这个过程就是Vue的生命周期。浅显的来说,生命周期的钩子函数就是回调函数,在不同的阶段有不同的回调函数供用户处理自定义的事件。也可以说生命周期是一套流程,而这套流程里面的方法会有先后顺序的执行(调用就执行,不调用就不执行)。
生命周期钩子
从上面的图中会看到生个vue的生命周期钩子:
- beforeCreate 
- created 
- beforeMount 
- mounted 
- beforeUpdate 
- updated 
- beforeDestroy 
- destroyed 
当然除了实例的生命周期,还有其他的:
- activated: keep-alive 缓存组件激活时使用
- deactivated: keep-alice 缓存组件停用时使用
- errorCaptured: 捕获一个来自子孙组件的错误时调用
beforeCreate 之前
在beforeCreate生命周期之前。首先是使用new Vue来开始创建一个Vue实例、接下来会初始化这个实例的生命周期事件。如下图:
 
| 12
 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
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>vue2.x生命周期学习</title>
 <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
 </head>
 <body>
 <div id="app"> <h1>{{message}}</h1></div></body>
 <script>
 var vm = new Vue({
 el: '#app',
 data: {
 message: "舒丽琦"
 },
 methods: {
 getMessage() {
 return `方法返回:${this.message}`;
 }
 },
 beforeCreate () {
 console.log("------beforeCreate------");
 console.log("el:", this.$el);
 console.log("data:", this.$data);
 console.log("methods:", this.getMessage);
 },
 })
 </script>
 </html>
 
 | 
打印结果:
| 12
 3
 4
 
 | ------beforeCreate------el: undefined
 data: undefined
 methods: undefined
 
 | 
beforeCreate 和 created 之间
在这个生命周期之前,会初始化当前实例上的data 和methods。说明created的时候数据已经绑定,是可以访问到了。在这里可以做ajax请求了。
注意:这里还没有 el 选项。
 
| 12
 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
 31
 32
 33
 34
 35
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>vue2.x生命周期学习</title>
 <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
 </head>
 <body>
 <div id="app"> <h1>{{message}}</h1></div></body>
 <script>
 var vm = new Vue({
 el: '#app',
 data: {
 message: "舒丽琦"
 },
 methods: {
 getMessage() {
 return `方法返回:${this.message}`;
 }
 },
 beforeCreate () {
 console.log("------beforeCreate------");
 console.log("el:", this.$el);
 console.log("data:", this.$data);
 console.log("methods:", this.getMessage);
 },
 created () {
 console.log("------created------");
 console.log("el:", this.$el);
 console.log("data:", this.$data.message);
 console.log("methods:", this.getMessage());
 }
 })
 </script>
 </html>
 
 | 
结果打印:
| 12
 3
 4
 5
 6
 7
 8
 
 | ------beforeCreate------el: undefined
 data: undefined
 methods: undefined
 ------created------
 el: undefined
 data: 舒丽琦
 methods: 方法返回:舒丽琦
 
 | 
可以看出,created可以获取data和methods
created 和 beforeMount 之间的生命周期
 
这阶段里面首先会判断是否有el选项。如果有的话,那么继续往下编译,如果没有el选项。则停止编辑。也就意味停止了生命周期。直到该Vue实例上调用了Vm.$mount(el)。
| 12
 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
 31
 32
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>vue2.x生命周期学习</title>
 <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
 </head>
 <body>
 <div id="app"> <h1>{{message}}</h1></div></body>
 <script>
 var vm = new Vue({
 
 data: {
 message: "舒丽琦"
 },
 methods: {
 getMessage() {
 return `方法返回:${this.message}`;
 }
 },
 created() {
 console.log("------created--------")
 },
 beforeMount() {
 console.log("------beforeMount------");
 console.log("el:", this.$el);
 console.log("data:", this.$data.message)
 console.log("methods:", this.getMessage());
 },
 })
 </script>
 </html>
 
 | 
结果打印:
手动调用实例的Vm。$mount(#app):
| 12
 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
 31
 32
 33
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>vue2.x生命周期学习</title>
 <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
 </head>
 <body>
 <div id="app"> <h1>{{message}}</h1></div></body>
 <script>
 var vm = new Vue({
 
 data: {
 message: "舒丽琦"
 },
 methods: {
 getMessage() {
 return `方法返回:${this.message}`;
 }
 },
 created() {
 console.log("------created--------")
 },
 beforeMount() {
 console.log("------beforeMount------");
 console.log("el:", this.$el);
 console.log("data:", this.$data.message)
 console.log("methods:", this.getMessage());
 },
 })
 vm.$mount("#app");
 </script>
 </html>
 
 | 
结果打印:
然后会判断是否有template。有没有template对生命周期没有影响。
- 如果有template则直接作为模板编译成render函数;
- 如果没有template则直接将外部的html作为模板编译;
注意:template模板的优先级要高于外部html的优先级。
如下的例子:
| 12
 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
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>vue2.x生命周期学习</title>
 <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
 </head>
 <body>
 <div id="app">
 <span>这是外部的html模板:{{message}}</span>
 </div>
 </body>
 <script>
 var vm = new Vue({
 el: '#app',
 data: {
 message: "舒丽琦"
 },
 template: "<span>这是内部的模板:{{message}}</span>",
 methods: {
 getMessage() {
 return `方法返回:${this.message}`;
 }
 }
 })
 </script>
 </html>
 
 | 
打开之后,我们看到的页面文案是:”这是内部的模板:舒丽琦”
如果我们把template 删除掉那么就会显示:”这是外部的html模板:舒丽琦”6
beforeMount 和 mounted之前的生命周期
 
这期间Vue实例对象添加$el。把内存中渲染好的html 替换到页面上。覆盖$el指定的页面。因为在这之前的beforeCreate生命周期打印的el还是undefined。
mounted生命周期
| 12
 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
 31
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>vue2.x生命周期学习</title>
 <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
 </head>
 <body>
 <div id="app">
 <span>这是外部的html模板:{{message}}</span>
 </div>
 </body>
 <script>
 var vm = new Vue({
 el: '#app',
 data: {
 message: "舒丽琦"
 },
 template: "<span>这是内部的模板:{{message}}</span>",
 methods: {
 getMessage() {
 return `方法返回:${this.message}`;
 }
 },
 mounted() {
 console.log("--------mounted--------");
 console.log("el:", this.$el);
 }
 })
 </script>
 </html>
 
 | 
打印结果为:
| 12
 
 | --------mounted--------el: <span>这是内部的模板:舒丽琦</span>
 
 | 
在这之前的span标签的名字是  占位的。这是JavaScript中的虚拟DOM形式存在的。在mounted之后就可以看到了内容发生了变化。
beforeUpdate 和 updated 之间的生命周期
 
从图中可以看出来, 当data的数据发生了变化,先会触发beforeUpdate钩子。注意这时候页面的视图还没更新。然后才重新渲染组件。最后调用updated。调用完之后。视图和data都是最新的。
我们看下面的例子:
| 12
 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
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>vue2.x生命周期学习</title>
 <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
 </head>
 <body>
 <div id="app">
 <span>这是外部的html模板:{{message}}</span>
 </div>
 </body>
 <script>
 var vm = new Vue({
 el: '#app',
 data: {
 message: "老的数据"
 },
 beforeUpdate() {
 console.log("--------beforeUpdate--------");
 console.log("el:", this.$el);
 },
 updated() {
 console.log("--------updated--------");
 console.log("el:", this.$el);
 }
 })
 vm.message = "新的数据";
 </script>
 </html>
 
 | 
打印结果:
 
当数据data有改变的( vm.message = “新的数据”)。就会分别触发beforeUpdate 和 updated。
beforeDestroy 和 destroyed 之间的生命周期
 
beforeDestroy 生命周期是在实例被销毁之前调用。在这一步,实例仍然是可用的。
destroyed生命周期是在实例销毁之后调用。调用后。Vue实例所指的所有东西都会被解除绑定。所有的事件也会被移除。所有的子实例也会被销毁。
activated
keep-alive 缓存组件激活的时候使用
deactivated
 keep-alive 缓存组件停用时使用
errorCaptured
捕获子孙组件的错误时调用
数据请求在created和mouted的区别
created是在组件实例一旦创建完成的时候立刻调用,这时候页面dom节点并未生成,mounted是在页面dom节点渲染完毕之后就立刻执行的,触发时机上created是比mounted要更早的:两者相同点:都能拿到实例对象的属性和方法;讨论这个问题本质就是触发的时机,放在mounted请求有可能导致页面闪动(页面dom结构已经生成),但如果在页面加载前完成则不会出现此情况建议:放在create生命周期当中