父组件如下:
// parent.vue
<template>
<a-form>
<a-form-item>
<a-input v-model="details.val1"></a-input>
</a-form-item>
<a-form-item>
<a-select v-model="details.val2">
<a-select-option
v-for="item in dictionary"
:value="item.code"
:key="item.code"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<Child :value="{ code: details.code, name: details.name }"></Child>
</a-form-item>
</a-form>
</template>
<script>
import Child from './Child.vue'
export default {
components: { Child },
data() {
return {
dictionary: [],
details: {}
}
},
created() {
setTimeout(() => {
this.dictionary = [
{
code: 1,
name: 'A'
},
{
code: 2,
name: 'B'
}
]
}, 500)
setTimeout(() => {
this.details = {
val1: 'text test',
val2: 1,
code: '123',
name: 'doorgod'
}
}, 1000)
}
}
</script>
子组件:
// Child.vue
<script>
export default {
props: {
value: Object
},
watch: {
value(val) {
console.log(val)
// do sth
}
}
}
</script>
这里存在一个问题,子组件内的监听函数会出现多次,dictionary以及details变更的时候都会触发,input以及select值变更的时候也会触发,跟预期的detail.code detail.name 变更触发相差甚远。
原因在于:
{} != {} // true
{} !== {} // true
每当parent中数据变化重新渲染时,Child的value都是一个新对象,所以会触发监听。
解决方案:
// parent.vue
<template>
<a-form>
<a-form-item>
<a-input v-model="details.val1"></a-input>
</a-form-item>
<a-form-item>
<a-select v-model="details.val2">
<a-select-option
v-for="item in dictionary"
:value="item.code"
:key="item.code"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<Child :value="obj"></Child>
</a-form-item>
</a-form>
</template>
<script>
import Child from './Child.vue'
export default {
components: { Child },
data() {
return {
dictionary: [],
details: {},
obj: {}
}
},
created() {
setTimeout(() => {
this.dictionary = [
{
code: 1,
name: 'A'
},
{
code: 2,
name: 'B'
}
]
}, 500)
setTimeout(() => {
this.details = {
val1: 'text test',
val2: 1,
code: '123',
name: 'doorgod'
}
this.obj = {
code: this.details.code,
name: this.details.name
}
}, 1000)
}
}
</script>
此时若details会更新,但是code,name不变也会触发,要完全符合预期需要:
this.obj.code = this.details.code
this.obj.name = this.details.name
且Child中监听value的属性
// Child.vue
watch: {
'value.code'(val) {
console.log(val)
},
'value.name'(val) {
console.log(val)
}
}
然而代码量多了一堆。。。