直接操作 Vue data 中不存在的属性导致的 v-model 绑定异常问题

直接操作 Vue data 中不存在的属性导致的 v-model 绑定异常问题

初学Vue遇到的问题,尝试了几个小时才搞明白,大佬应该一眼就能看出什么问题吧……

需要注意,不要直接在JS中操作一个Vue data对象中不存在的属性,如果同时有通过v-model绑定到该对象的不存在的属性时,会出现诡异的行为表现,console中不会报出任何 warnerror

需求是,实现三个复选框,第一个复选框初始为选中状态,一开始写出来是这样的——

HTML
1
2
3
4
5
<div id="app" style="margin: 10px;">
<van-checkbox v-for="box in checkboxes" :key="box.id" v-model="box.selected">
复选框 {{ box.title }}
</van-checkbox>
</div>
JS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
new Vue({
el: '#app',
data () {
return {
checkboxes: [
{ id: 1, title: 'a' },
{ id: 2, title: 'b' },
{ id: 3, title: 'c' }
]
}
},
created () {
this.checkboxes[0].selected = true
}
})

试下效果:

See the Pen vue-v-model-not-work by iMaeGoo (@iMaeGoo) on CodePen.

复选框a的表现显然是异常的,点击不能成功地切换选中状态,而在点击之后再点击其他复选框,才会“有延迟地”切换状态。

为什么会这样?

尝试在created方法的末尾打印出this.checkboxes[0]——

发现 idtitle 都变成了 getter/setter 的形式,而 selected 仍然是独立的属性。

后续查询发现,Vue 官方文档 - 深入响应式原理 的第一段话是——

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setterObject.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。

created 方法中,我尝试直接对 Vue data 对象中的属性操作,而 v-model 需要使用 getter/setter 操作,二者即产生了冲突。

解决方式 1

在 data 中添加 selected 属性,即使初值为undefined或者null,也能够让 Vue 正确识别所有对象属性。

JS
1
2
3
4
5
6
7
8
9
data () {
return {
checkboxes: [
{ id: 1, title: 'a', selected: undefined },
{ id: 2, title: 'b', selected: undefined },
{ id: 3, title: 'c', selected: undefined }
]
}
}

解决方式 2

在JS中操作原本不存在的属性时,使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性

JS
1
2
3
4
created () {
// Vue.set 等同 this.$set
this.$set(this.checkboxes[0], 'selected', true)
}
# js, vue

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×