对于vuejs中自定义组件v-model的一些疑问
代码比较简单,直接如下
<template><div id="app">
<button @click="_add">父组件按钮点击</button>
<ul>
<li v-for="(item,index) in message" :key="index">
{{item.name}}
</li>
</ul>
<hr>
<children v-model="message"></children>
</div>
</template>
<script>
import children from './components/children'
export default {
name: 'app',
components: {
children
},
data(){
return{
message: []
}
},
methods: {
_add(){
this.message.push({
name:'name1'
})
},
},
}
</script>
<template><div class="children">
<button @click="_add">子组件按钮点击</button>
<ul>
<li v-for="(item,index) in message" :key="index">
{{item.name}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "children",
props: {
value: {
type: Array
},
},
data() {
return {
message: []
}
},
watch:{
value(newVal){
this.message = newVal
}
},
methods: {
_add(){
this.message.push({
name:'name2'
})
},
},
};
</script>
点击父按钮会正常传递数据到子组件,如图:
只点击子组件因为没有 emit 传值显示也是正常,如图:
但是问题来了,如果先点击一次父按钮,再点击子组件里面的按钮,这时为什么会触发父组件数据更新?如图:
其中的 name1 是第一次先点击父组件的结果,name2 是第二次点击子组件按钮出现的结果。
在官网的介绍当中,说如果要更新父组件的数据,需要手动 emit 触发更新,目前遇到的这种情况不是很明白为什么会自动触发更新数据。
请前辈们解答下这个疑问~~~
回答
数据类型的问题,当前数据类型是数组,子组件监听赋值的时候相当于共享了内存地址,可以试试楼上说的深拷贝,但是如果是基于数组对象等复杂数据机构,需要特殊的深拷贝方法;
// 子组件修改<template>
<div class="children">
<button @click="_add">子组件按钮点击</button>
<ul>
<li v-for="(item, index) in message" :key="index">
{{ item.name || item }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "children",
props: {
value: {
type: Array
}
},
data() {
return {
message: []
};
},
watch: {
value(newVal) {
this.message = newVal;
}
},
methods: {
_add() {
// this.message.push({
// name: "name2"
// });
this.message += "¥子¥";
}
}
};
</script>
// 父组件修改<template>
<button @click="_add">父组件按钮点击</button>
<ul>
<li v-for="(item, index) in message" :key="index">
{{ item.name || item }}
</li>
</ul>
<hr />
<children v-model="message"></children>
</template>
<script>
export default class App extends Vue {
// private message: { name: string }[] = [];
private message = "";
public _add() {
this.message += "$父$";
// this.message.push({
// name: "name1"
// });
}
}
</script>
如上改用非复杂数据类型不会出现题主说的问题
这是因为子组件的 message
不是由父组件直接传递进来的参数,而是自己声明的属性,只是在 watch.value
函数执行后才由父组件传入的 value
改写,在父组件改写message
前,二者并不相关。
如果你在子组件的 mounted
函数里写:
console.log(this.message === this.value);
理应为 false
;
但如果在 watch.value
的末尾写同样的代码,输出理应为 true
。
如果你给父子组件的初始 message
传不同的值的话,他们在首屏的显示必然是不一样的,这也能证明此时二者还不是同一个东西。
如果想使二者始终一致的话,子组件里的 message
应为 prop
:
props: { message: {
type: Array,
default: () => []
},
},
兄弟我试了下,如果 v-model 绑定的不是一个数组,而是一个布尔值,就不会出现你的这种情况,可能是数组比较特殊吧!或者这是个 bug,或者你对数组进行深拷贝试下
<template> <div class="children">
<button @click="_add">子组件按钮点击</button>
<ul> <li v-for="(item,index) in message" :key="index">
{{item.name}}
</li>
</ul> </div></template>
<script>
export default {
name: "children",
props: {
value: {
type: Array
},
},
data() {
return {
message: []
}
},
watch:{
value(newVal){
this.message = JSON.parse(JSON.stringify(newVal));
}
},
methods: {
_add(){
this.message.push({
name:'name2'
})
},
},
};
</script>
以上是 对于vuejs中自定义组件v-model的一些疑问 的全部内容, 来源链接: utcz.com/a/85493.html