前言
我记得尤大已经说过,你看 Vue 源码干嘛?你应用 Vue 又不须要它的源码,你只须要会用就行了!
然而咱们得卷啊,不卷怎么怀才不遇😥,我还记得在往年的蓝桥杯群里,有一起届的还不晓得哪个大学的哥们,曾经在读 Vue/React/Node 的源码了 ….. 作为小菜鸡的我看着大佬娓娓而谈,在群角落里瑟瑟发抖。
最近有在牛客上温习 Vue 的常识,整顿出这篇文章,一是不便本人将来温习,二是心愿可能帮忙一些跟我一样的敌人们温习一边知识点,学习在什么时候都不晚。
这篇文章会讲到:
Vue 的生命周期到底是什么
Vue 生命周期的执行程序
生命周期的每个阶段适宜做什么
咱们的申请放在哪个生命周期会更适合
当然我只会讲我了解的 emm,可能会很浅,还请多包涵。
Vue 的生命周期到底是什么?
与其说是 Vue 的生命周期,我感觉不如说是其内组件的生命周期。简略来说,它的生命周期就是用来形容一个组件从引入到退出的全过程。那简单来说呢?就是一个组件从创立开始经验了数据初始化,挂载,更新等步骤后,最初被销毁。
Vue 生命周期的执行程序
他整体是分为三个大阶段的,在三个大阶段中,有细分为若干的小阶段。咱们能够在不同的阶段去做不同的事件,后文也会讲到不同的阶段适宜咱们去做具体什么事件的。
咱们先来看看它的执行程序吧:
有两种办法,一种就是 Vue 的官网文档下面有一个图是专门解释生命周期的,但鉴于可能许多小伙伴们都是跟我一样,看英文文档都要随同着翻译的程度,所以特意在网上找了个翻译过后的汉化版,放在这里给大家做参考:
这个图具体的解释了一个 Vue 实例从创立到销毁的全过程。
第二种办法,就是咱们在 Vue 我的项目中打印一下,在控制台中咱们就能清晰的看出,谁执行的早,谁执行的晚,甚至能看出他们有什么区别:
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)
}
复制代码
挂载阶段
其实这个代码的先后顺序就是他执行的先后顺序了,为了能有更新的状态,所以我找了个 todolist 的 demo,能够增加跟删除的,不便咱们来看,首先是刚进入页面:
咱们能够看到 beforeCreate 是最先的,并且在此时的状态下,咱们打印的信息什么都拿不到。
之后进入了 created 状态,在这个状态中咱们的 el,也就是 Dom 元素仍旧是拿不到的,然而咱们曾经能够拿到 data 了,这意味着 created 曾经将数据加载进来了,曾经为这个 Vue 实例开拓了内存空间。
beforeMount,挂载前状态,在我的了解挂载就是将虚构 Dom 转变成实在 Dom 的过程,所以在这之前,咱们的 el 当然还是拿不到的。
mounted,挂载完结,意味着虚构 Dom 曾经挂载在了实在的元素上,所以从此开始咱们就能够拿到 el 了。咱们能够用 console.dir 去打印一些咱们须要的元素的属性。
至此,咱们的挂载阶段就完结了。
更新阶段
上面咱们删除一个 list,来看一下更新状态。
每当咱们去扭转页面元素的时候,就会进入更新阶段,也就是 beforeUpdate,updated 这两个状态。
销毁阶段
上面咱们再来看一下最初的销毁阶段。
beforeDestroy,销毁前状态,在销毁之前,所以咱们的元素、data 都是如同挂载之后的阶段一样,都是能够打印进去的。
destroyed, 其实最让我震惊的是这个,销毁实现的状态,我认为销毁了,那应该什么都打印不进去了,其实不然,他还是什么都能够打印进去的。
beforeDestroy 和 destroyed,都是咱们来到这个组件才会被调用的生命周期。
生命周期的每个阶段适宜做什么
上面咱们来讲讲,在不同的阶段咱们能够做些什么:
created:在 Vue 实例创立结束状态,咱们能够去拜访 data、computed、watch、methods 上的办法和数据,但当初还没有将虚构 Dom 挂载到实在 Dom 上,所以咱们在此时拜访不到咱们的 Dom 元素(el 属性,ref 属性此时都为空)。
咱们在此时能够进行一些简略的 Ajax,并能够对页面进行初始化之类的操作
beforeMount:它是在挂载之前被调用的,会在此时去找到虚构 Dom,并将其编译成 Render
mounted:虚构 Dom 曾经被挂载到实在 Dom 上,此时咱们能够获取 Dom 节点,$ref 在此时也是能够拜访的。
咱们在此时能够去获取节点信息,做 Ajax 申请,对节点做一些操作
beforeupdate:响应式数据更新的时候会被调用,beforeupdate 的阶段虚构 Dom 还没更新,所以在此时仍旧能够拜访现有的 Dom。
咱们能够在此时拜访现有的 Dom,手动移除一些增加的监听事件
updated:此时补丁曾经打完了,Dom 曾经更新结束,能够执行一些依赖新 Dom 的操作。
但还是不倡议在此时进行数据操作,防止进入死循环(这个坑我已经踩过)
beforeDestroy:在 Vue 实例销毁之前被调用,在此时咱们的实例还未被销毁。
在此时能够做一些操作,比方销毁定时器,解绑全局事件,销毁插件对象等
父子组件的生命周期
刚刚说的都是单页面,那么父子组件的生命周期会是什么样子呢?咱们仅做一个简略的补充。
不晓得大家在刚刚的图中是否留神到了这两行:
咱们页面中的小 li 就是一个被嵌入在这个大页面外部的一个子组件,咱们也打印了它的生命周期:
created() {
console.log('list created')
},
mounted() {console.log('list mounted')
},
beforeUpdate() {console.log('list before update')
},
updated() {console.log('list updated')
},
beforeDestroy() {
// 及时销毁,否则可能造成内存泄露
console.log('list beforeDestroy')
},
destroyed(){console.log('list Destroy')
}
复制代码
由此可得,在父组件挂载前阶段,子组件曾经挂载实现了。
不光是挂载阶段,其余两个阶段咱们也能够打印进去,然而在这里我就不细说了,间接上论断:
挂载阶段:父组件 beforeMount -> 子组件 created -> 子组件 mounted -> 父组件 mounted
更新阶段:父组件 beforeUpdate -> 子组件 beforeUpdated -> 子组件 updated -> 父组件 updated
销毁阶段:父组件 beforeDestroy -> 子组件 beforeDestroy -> 子组件 destroyed -> 父组件 destroyed
咱们的申请放在哪个生命周期会更适合
那么至此咱们曾经对于 Vue 的生命周期有了一个根本的理解,当初咱们来说一说,咱们的申请应该放到哪个生命周期中才最为适合。
一般来说,会有两种答复:created 和 mounted。上文曾经讲了,这两个答复,前者是数据曾经筹备好了,后者是连 dom 也曾经加载实现了,那么到底哪个才是正确答案呢?
其实,两个都是能够的,然而 mounted 会更好。
可能有人会说:created 的工夫会更早,早些调用不是会省很多工夫吗?这样性能会不会更高一点
别急,咱们一点一点来看
首先,它的确是早了,然而早不了几微秒,所以这其实没有进步性能
其次,咱们在 created 阶段并没有去做渲染,所以在接下来咱们会去做 Dom 渲染,然而如果此时咱们还做了 Ajax 操作,在 Ajax 完结之后就会返回数据,咱们就会将其插入到主线程中去运行,去解决数据,然而咱们要晓得,在浏览器机制中,渲染线程跟 js 线程是互斥的,所以有可能咱们做渲染的同时,另一边可能要解决 Ajax 返回的数据了,这时候渲染就有可能被打断,在解决完数组后,去进行从新渲染。
那如果在 created 中有多个 Ajax 呢?咱们又要从新进行渲染,所以在 created 去做 Ajax 申请这显著不太适合。
还有,有的时候咱们接到返回的数据的时候可能要在回调函数中去进行一些 Dom 的操作,可是 created 阶段咱们还没有将实在 Dom 加载进去,所以相对而言咱们还是在 mounted 去调用要好一些
如果是服务端渲染,咱们将其放入 created 中进行,因为服务端不反对 mounted。
最初
如果你感觉此文对你有一丁点帮忙,点个赞。或者能够退出我的开发交换群:1025263163 互相学习,咱们会有业余的技术答疑解惑
如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点 star: https://gitee.com/ZhongBangKe… 不胜感激!