接触Vue两个月了,今天说一说vue里边很重要的生命周期,记得最开始接触的时候我问了一下周边的同事,
这些生命周期都有什么用,得到的答案是mounted里边可以操作属性,你记住mounted就完事了,于是乎。。。
数据请求,mounted() 赋值 mounted(),执行方法,mounted(), 监听更新数据???搞不动了。。。
然后最近仔细的看了一遍Vue的生命周期,今天和大家分享一下我所了解的
首先 什么是Vue的生命周期
Vue 实例从开始创建、初始化数据、编译模板、挂载Dom和渲染、更新和渲染、卸载等一系列过程,这是 Vue 的生命周期
vue的生命周期里边有八个生命周期钩子函数分别是
beforeCreat() 创建前
created()创建
beforeMount()挂载前
mounted()挂载
beforeupdate()更改前
updated()更改
beforeDestroy()销毁前
destroyed()销毁
先来一张官方的生命周期图镇贴
beforeCreate 实例创建前
这个生命周期如上图所示 实例初始化在这个生命周期遍历 data 对象下所有属性将其转化为 getter/setter
也就是说添加一个被观察者,所以我们平时在项目中遇到在后来添加新的属性视图不更新就是这个原因
在后来被添加的属性,没有被放到观察者对象中去 但是这个时候数据并没有和模板建立链接 还不能操作属性
说到这里你可能会反驳我,打印的全都是undefined,你怕是在逗我
but 你可以通过$options(实例自定义属性,属于数据访问的一种和$date 平级) 看到data的值 注意data是个函数 他没执行 所以拿不到数据,用图来说话
data(){ return{ a:"1" } }, beforeCreate(){ console.log("beforeCreate",this.$el,this.a) }, //beforeCreate undefined undefined
那么如果想在实例挂载完成后添加的属性触发视图更新的话可以用 $set 这个方法 这个方法会向被观察者对象里边新增你的属性
这时候我们打印一下组件里的属性还是不存在的
created 实例创建
到这个生命周期的时候 实例已经被创建完毕 属性已经绑定 属性是可以操作的
但是dom还不存在 $el属性还不可以操作
这个生命周期可以进行axios请求 但是这个时候页面还没有被渲染出来 如果请求时间过长的话 会出现长时间的白屏
加loading可能会用户体验好一些
这个生命周期如上图所示 他会把template模板编译成html 还有执行render函数,返回一个虚拟dom 同第一句话 就是说
dom还拿不到
data(){ return{ a:"1" } }, beforeCreate(){ console.log("beforeCreate",this.$el,this.a) }, created(){ console.log("created",this.$el,this.a) this.a=2 console.log(this.a) }, //created undefined 1 //2
这个虚拟Dom接触的不是太多 简单来讲就是通过js生成一个类似于dom树的那么一个东西
来看一下这个虚拟dom
大概就是这么一大串 ,刚看到的时候我的第一感觉就是 真¥%…#…复杂 然后出于好奇 我打印了一下真实dom
更¥%……%复杂总而言之 一屏放不下 所以说大批量的操作dom 是很影响性能的一件事情 膜拜一下远方的各位大神
beforeMount 挂载前
从图上来讲 这个声明周期做的是模板编译,看网上的帖子有人能把$el打印出来 不太理解怎么打印出来的 自己试了一下
打印不出任何东西
beforeMount(){ console.log('beforeMount',this.$el,this.pickerMark) debugger }, //beforeMount undefined false
这个生命周期 el还未对数据进行渲染 还是不能操作dom
mounted挂载
这个生命周期 是我用的最多的 这个时候的虚拟dom已经被渲染到了真实的dom上边
这个生命周期里边我们可以做的事情很多 比如数据请求或者赋值操作属性等等
mounted(){ console.log('mounted',this.$el,this.pickerMark) }, //mounted <div class="propaganda-form" arealistitem="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" style="display: none;"></div> false
以上四个生命周期 每个组件只执行一次,过去了就不会在执行了
beforeUpdate 更新前 Updated 更新
我们在mounted更新一个属性的话 beforeUpdate 和 updated 生命周期函数 会被触发 但是仅限于 被观察的属性做出的变化且被引用他们才会触发
而且需要注意的是 不要再updated 函数里边直接就修改属性 会进入死循环 比如说。。。。
浏览器崩溃了。。。。 如果你要用的话 一定要加判断条件 确保能跳出去的那种,我个人是很喜欢用updated这个生命周期函数的
因为之前我拿值什么的都是用的watch 但是vue并不推荐用 原因说是很耗费资源 不算计算属性的话 这个updated 可以说是很方便了
但是如果变化的不是响应式的值 他就不会触发怎么办 之前研究过一个方法分享一下 就是说再date里边声明一个变量当作标记
然后把这个变量放到页面中 dispaly:none; 然后在你调用非相应的变量的时候 你在后边也调用一下这个标记 updated生命周期函数
是会执行的 这时候你可以加一些判断在update去执行一些东西 当然 后来认识了计算属性 就放弃了这个做法 计算属性是一种声明式的属性
他只会告诉你这个值是怎么构成的 很方便
beforeDestroy 销毁前 destroy销毁
这两个生命周期 用到的比较少 顾名思义 销毁前这个生命周期 的时候 还是可以对元素进行操作的
之前在项目中用到的就是 高级搜索在销毁的时候判断是否有值 然后返回相应的状态
销毁这个生命周期执行过后 实例的属性和方法就不能再用了
生命周期的顺序
上边讲了单个实例的生命周期,但是我们在平时用到的 肯定不会是一个组件, 那么父子组件 或者兄弟组件的生命周期又是什么样的
直接来一张图
上图可以看到 如果有父子组件的话 会先从父组件开始 到beforeMount 开始走子组件 到beforeMount 然后是子组件的一堆mounted 最后父组件
还可以看出 兄弟组件的话 是依次到beforeMount 然后按照顺序mounted
再来看一下update
有关联的话 他的顺序是 父beforeupdate 子beforeupdate 子updated 父updated
父组件没有关联的话 也不会触发子组件的生命周期
销毁也是这个顺序 就不一一上图了
大家 可以理解成递归 感觉就是递归 ,那么如果递归的话 就存在一个作用域的问题 混入的时候 又是什么样的
大家都知道混入的时候组件里边属性和方法 会优先使用 但是生命周期是都会走的 相比大家猜也都猜到了
既然组件里边有方法的话会用组件的 那么混入必然是最外层的 刚才证实了一下想法 确实是这样
混入的生命周期的话 会在每个声明周期的最前边 所有的生命周期 都会优先执行
以上是对vue生命周期的理解 可能有不足之处 希望大家批评指正