直接操作 Vue data 中不存在的属性导致的 v-model 绑定异常问题
初学Vue遇到的问题,尝试了几个小时才搞明白,大佬应该一眼就能看出什么问题吧……需要注意,不要直接在JS中操作一个Vue data对象中不存在的属性,如果同时有通过v-model绑定到该对象的不存在的属性时,会出现诡异的行为表现,console中不会报出任何warn或error。需求是,实现三个复选框,第一个复选框初始为选中状态,一开始写出来是这样的——HTML12345<div id="a
初学Vue遇到的问题,尝试了几个小时才搞明白,大佬应该一眼就能看出什么问题吧……
需要注意,不要直接在JS中操作一个Vue data对象中不存在的属性,如果同时有通过v-model
绑定到该对象的不存在的属性时,会出现诡异的行为表现,console
中不会报出任何 warn
或 error
。
需求是,实现三个复选框,第一个复选框初始为选中状态,一开始写出来是这样的——
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 } }) |
试下效果:
复选框a的表现显然是异常的,点击不能成功地切换选中状态,而在点击之后再点击其他复选框,才会“有延迟地”切换状态。
为什么会这样?
尝试在created
方法的末尾打印出this.checkboxes[0]
——
发现 id
和 title
都变成了 getter/setter 的形式,而 selected 仍然是独立的属性。
后续查询发现,Vue 官方文档 - 深入响应式原理 的第一段话是——
当你把一个普通的 JavaScript 对象传入 Vue 实例作为
data
选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty
把这些属性全部转为getter/setter
。Object.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) } |
- 本文标题:直接操作 Vue data 中不存在的属性导致的 v-model 绑定异常问题
- 本文作者:iMaeGoo
- 发布时间:2019-10-24 20:10
- 本文链接:https://www.imaegoo.com/2019/vue-model-not-work/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0 许可协议。转载请注明出处!
//关于props 和 v-model 和 $set () 和 $focusUpdate() 方法的 理解和使用
1 props
* 1 子组件可以直接修改父组件的数组和对象,并且父组件会跟着改变,可能是因为两个数据
* 指向同一个内存位置。
* 2 如果直接修改string类型的惠报错
* 3 如果修改json 数组中的item 的值的时候深度监听的时候是可以监听到的。
2 v-model
一般情况下如果v-mode 绑定了一个没有被定义的属性,这个时候不可以直接修改这个属性
可以使用 that.$set(that.detail[idx],'selected',false) 方法修改这个不存在的属性,不然会报错
3 如果是数组和对象 你 直接使用 this.arry[0] = 1 类似的操作是不会自动检测到更新的,
1)然而你可以使用 this.$focusUpdate 方法
强制刷新。
2)或者你data中的数据保存一份到自定义的变量中,然后再次 把这个变量放回去,
3) 使用推荐的方法比如 this.array.pop() 这个pop 方法会被检测到。
* 4 如果是给数组对象中新增一个key 那么深度监听也监听不到
that.$set(that.detail[idx],'selected',false)
* 这个方法添加对象中的一个key的值,这样同样会触发更新。
更多推荐
所有评论(0)