[Vue.js] v-model 绑定对象不实时更新

JavaScript 做棵大树 4年前 (2020-07-13) 2820次浏览 2个评论
文章目录[隐藏]

在最近参与的一个项目中,前端用到了 vue.js 框架,期间有个功能需要动态的向一个被绑定的对象中添加属性。但是在实际应用中问题出现了:在向对象中添加属性后,与对象绑定的组件内容却未发生变化,必须要再次刷新组件,其内容才会变为更改后的内容。

起初我以为是属性没有添加成功,因为在我的印象中 v-model 是双向绑定的,不会出现不更新的状态。在我查看 Devtools 中的监控后,发现对应的对象确实添加了指定的属性。

于是,我前去查看了官方文档,找到了官方给出的解释:Vue.js 如何追踪变化

官方解释

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

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

[Vue.js] v-model 绑定对象不实时更新

检测变化的注意事项

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。

对于对象

Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:

var vm = new Vue({
  data:{
    a:1
  }
})

// `vm.a` 是响应式的

vm.b = 2
// `vm.b` 是非响应式的

对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如,对于:

Vue.set(vm.someObject, 'b', 2)

您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:

this.$set(this.someObject,'b',2)

有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign()_.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

这是对于对象赋值的解决方式,在采用了官方的解决方案 this.$set(object, key, value) 后确实实现了实时更新的效果。同时对于数组等情况,可查看 余下官方文档

为什么会这样呢?

如官方所说 “由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。” ,但是为什么会这样呢?

借用 Segmentfault UKer 的回答:

ECMAScript 中有两种属性:数据属性访问器属性;
数据属性的描述符为:Configurable,Enumerable,Writable,Value;
访问器属性的描述符为:Configurable, Enumerable,set,get。

当我们使用new Vue(obj),其内部发生了大体如下代码的转换,即,将数据属性转换为了访问器属性

function Vue(obj){
    obj.data.keys().forEach((prop, index) => {
      Object.defineProperty(obj.data, prop, {
        set(){
          //可以在此处进行事件监听
        },
        get(){

        }
      })
    })
    return obj;
 }

但是当我们后面再次使用普通的赋值,仅仅是赋值了一个数据属性的,这个属性是不会具有访问器属性的事件监听功能的。

至此,v-model 绑定数据不实时更新的问题方才得到了解决。


[Vue.js] v-model 绑定对象不实时更新


做棵大树 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明[Vue.js] v-model 绑定对象不实时更新
喜欢 (16)
[欢迎投币]
分享 (0)
关于作者:
一个整天无所事事的,有时候忽然热血的孩子
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(2)个小伙伴在吐槽
  1. 點讚!o( ̄▽ ̄)d幫到我了
    Zohan2022-02-04 13:56 回复 Windows 10 | Chrome 97.0.4692.99
    • 能帮到就很开心!
      做棵大树2022-03-08 15:51 回复 Windows 10 | Firefox浏览器 98.0