初学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/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)
}

#jsvue

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//关于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的值,这样同样会触发更新。 

 

Logo

前往低代码交流专区

更多推荐