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