生命周期函数顺序测试
created, mounted
父组件created子组件created子组件mounted父组件mounted
updated
无论是通过v-model在子组件更新父组件的数据,或直接在父组件修改传递给了子组件用的值,update的执行顺序都是
子组件updated父组件updated
重现代码
App.vue 这是父组件
<script>
import ShowComp01 from 'components/ShowComp01.vue'
export default {
name: 'App',
components: { ShowComp01 },
data() {
return {
akName: '张三',
age: '12',
}
},
methods: {
onChangeAge() {
this.age = '33'
},
},
created() {
console.log('>>>>>>>>>>>>>>>>App created')
console.log(this)
},
mounted() {
console.log('************App mounted')
},
updated() {
console.log('App更新')
},
}
</script>
<template>
<div>
<div
style="
border-bottom: 1px solid #333;
margin-bottom: 10px;
padding-bottom: 10px;
"
>
akName:{{ akName }}
<input type="text" v-model="age" />
<button @click="onChangeAge">修改age</button>
</div>
<ShowComp01 v-model="age"></ShowComp01>
</div>
</template>
<style lang="scss" scoped></style>
ShowComp01.vue 这是子组件
<template>
<div>
ShowComp01组件
<br />
age:{{ age }}
<input type="text" :value="age" @change="onChange" />
</div>
</template>
<script>
export default {
name: 'ShowComp01',
model: {
prop: 'age',
event: 'change',
},
props: {
age: {
type: String,
},
},
methods: {
onChange(val) {
this.$emit('change', val.target.value)
},
},
created() {
console.log('>>>>>>>>>>>>>>>>ShowComp created')
},
mounted() {
console.log('************ShowComp mounted')
},
updated() {
console.log('ShowComp更新')
},
}
</script>
<style scoped></style>
依赖defineProperty和观察者模式, vue是以组件为单位的精确更新
- 组件渲染顺序是从上至下依次渲染的
- 修改了仅在父组件中用的数据,子组件和兄弟组件是不会更新的
- 无论是在父组件修改了在子组件用到的数据,还是子组件通过v-model方式修改了父组件顺序,updated的执行顺序都是
先子组件updated,再父组件updated - 即时父组件将某个属性传递给了子组件,只要
子组件的界面未使用该属性,那么父组件更新该值时,子组件都时不会重新渲染的 - 只要
界面上用到的数据发生了改变,那么就会触发组件的rerender,否则不会(注意:是界面上用到的即template块中用到的)
随便更新一个input的值,加入断点,会发现是input所在组件发起的update操作
这里的prevVnode和vnode,表示的是DemoOne这个组件的虚拟DOM, prevVnode表示的是旧的虚拟DOM, 表示的是当前的虚拟DOM
__patch__方法内部会通过diff算法对比两个虚拟DOM的不同,然后做精确更新
看到这里的,你可能会有疑问,既然VUE每次都是精确更新,那为什么我项目里有些界面还是有卡顿?你是吹嘘了一个假的精确更新吧!
不要慌,请继续往下看,注意VUE是精确更新没错,但他是通过diff算法,筛选出了,仅哪些虚拟DOM对应的真实DOM,需要进行更新(注意:这里的更新不仅是指更新还包括删除dom和添加dom),diff算法也是要消耗时间的,越是复杂的界面,diff算法执行的时间越长
这里的children就是子虚拟DOM
重现代码
根组件
<script>
import DemoOne from 'components/DemoOne.vue'
import BrotherComp from 'components/BrotherComp.vue'
export default {
name: 'App',
components: { DemoOne, BrotherComp },
data() {
return {}
},
methods: {},
created() {
console.log('>>>>>>>>>>>>>>>>App created')
// console.log(this)
},
mounted() {
console.log('************App mounted')
},
updated() {
console.log('App更新')
},
}
</script>
<template>
<div>
<BrotherComp></BrotherComp>
<DemoOne></DemoOne>
</div>
</template>
<style lang="scss" scoped></style>
BrotherComp.vue兄弟组件
<template>
<p>兄弟组件</p>
</template>
<script>
export default {
name: 'BrotherComp',
created() {
console.log('>>>>>>>>>>>>>>>>兄弟组件 created')
},
mounted() {
console.log('>>>>>>>>>>>>>>>>兄弟组件 mounted')
},
updated() {
console.log('>>>>>>>>>>>>>>>>兄弟组件 updated')
},
}
</script>
<style scoped></style>
DemoOne.vue父组件
<script>
import ShowComp from 'components/ShowComp.vue'
export default {
name: 'DemoOne',
components: { ShowComp },
data() {
// console.log(p)
debugger
return {
akName: '张三',
age: '12',
info: {
country: '中国',
male: '男',
},
other: {
story: '有故事的人',
hobby: '玩',
},
parentName: {
father: '大张三',
mother: '张三之母',
},
}
},
method: {},
created() {
console.log('>>>>>>>>>>>>>>>>父组件 created')
// console.log(this)
},
mounted() {
console.log('************父组件 mounted')
},
updated() {
console.log('父组件更新')
},
}
</script>
<template>
<div>
<div
style="
border-bottom: 1px solid #333;
margin-bottom: 10px;
padding-bottom: 10px;
"
>
父组件
<br />
akName:{{ akName }}
<input v-model="akName" />
age:{{ age }}<input v-model="age" />
<br />
info:{{ info }}<input v-model="info.country" /><input
v-model="info.male"
/>
<input v-model="info.country" />
<br />
other {{ other }}<input v-model="other.story" />
<input v-model="other.hobby" />
<br />
parentName<input v-model="parentName.father" />
<input v-model="parentName.mother" />
</div>
<ShowComp
:age="age"
v-model="info"
:story="other.story"
:parentName="parentName"
:motherName="parentName.mother"
></ShowComp>
</div>
</template>
<style lang="scss" scoped></style>
ShowComp.vue子组件
<template>
<div>
子组件
<br />
age:{{ age }}
<br />
info:{{ info }} <input :value="info.male" @change="onChange" />
<br />
story:{{ story }}
<br />
parentName:{{ parentName.father }}
</div>
</template>
<script>
export default {
name: 'ShowComp',
model: {
prop: 'info',
event: 'change',
},
props: {
story: {
type: String,
},
age: {
type: String,
},
info: {
type: Object,
},
parentName: {
type: Object,
},
motherName: {
type: String,
},
},
methods: {
onChange(val) {
this.$emit('change', { ...this.info, male: val.target.value })
},
},
watch: {
motherName(newVal, oldVal) {
console.log('motherName监听', newVal, oldVal)
},
},
created() {
console.log('>>>>>>>>>>>>>>>>子组件 created')
},
mounted() {
console.log('************子组件 mounted')
},
updated() {
console.log('子组件更新')
},
}
</script>
<style scoped></style>
为什么写这个?
是因为看了 阿里的Formily 提到了精确渲染的概念,一看之下觉得牛逼哄哄,精确渲染,只渲染变动的部分,性能极佳
然后回想起我做过的项目,确实有一些表单场景是比较卡顿的,以前也没仔细了解过,为什么会卡顿,也没有好的解决方案,所以我就想,是不是以前那些界面卡顿,也是因为没有精确渲染的原因?
但貌似我想岔了,vue本身就是精确更新的。Formily貌似主要解决的是React 组件的渲染性能
最后虽然没有达到我预期的目的,但对于vue开发我又有了更近一步的了解
同时我也看到了一个比较有启发的文章: 一顿操作,我把 Table 组件性能提升了十倍