vue2为什么监听不到新增属性

fiy 其他 51

回复

共3条回复 我来回复
  • 不及物动词的头像
    不及物动词
    这个人很懒,什么都没有留下~
    评论

    问题背景:在vue2中,当给data对象新增一个属性时,vue无法自动检测到该属性的变化。

    解决方案:vue2的响应式系统只能检测已有的属性,无法检测新增的属性。但是我们可以通过一些方法来解决这个问题。

    1. 使用Vue.set进行属性的新增:

      Vue.set(obj, key, value):这个方法可以向响应式对象中添加一个具有响应式特性的属性,同时触发视图更新。

      示例代码:

      Vue.set(this.data, 'newProp', 'new value')
      
    2. 使用vm.$set进行属性的新增:

      Vue实例就是vm,vm.$set(obj, key, value) 方法与 Vue.set() 方法的功能相同,也可以用来新增属性。

      示例代码:

      this.$set(this.data, 'newProp', 'new value')
      
    3. 在组件的created或mounted生命周期钩子中使用this.$forceUpdate()手动触发更新。

      示例代码:

      created() {
        this.data.newProp = 'new value'
        this.$forceUpdate()
      }
      

    需要注意的是,以上两种方法都是在新增属性时触发视图更新,但是如果直接给对象赋值一个新的对象,即如下操作,依然无法触发更新:

    this.data = { ...this.data, newProp: 'new value' }
    

    综上所述,当我们需要在vue2监听新增的属性变化时,可以使用Vue.set()、vm.$set()或者手动调用vm.$forceUpdate()来解决这个问题。

    2年前 0条评论
  • worktile的头像
    worktile
    Worktile官方账号
    评论

    在Vue2中,当我们将一个对象传递给Vue实例的data选项时,Vue会利用“Object.defineProperty”将对象中的每个属性都转化为getter和setter,并且这些属性都会被添加到Vue实例的响应式系统中。这意味着,只有在初始化Vue实例时定义的属性才会被监听和观察到,而对于后续动态添加的属性,Vue是无法自动进行响应式处理的。

    以下是解释为什么Vue2监听不到新增属性的几个关键原因:

    1. 对象属性初始化的问题:Vue只会监听已经存在于data选项中的属性以及其子属性,所以当我们直接添加一个新属性时,Vue是无法自动被观察到的。这是因为Vue在初始化时会对data中的属性进行属性getter和setter的定义,但对于新增的属性没有定义相应的getter和setter。

    2. 对象新增属性的响应问题:由于Vue无法直接监听到新增的属性,所以当我们直接给对象添加一个新的属性时,Vue无法触发视图的更新。Vue只会在初始化时对data中的属性进行监听,当data中的属性发生变化时,才会触发视图的更新。

    3. 重新赋值的问题:即使我们使用Vue.set()方法将属性添加到对象中,Vue仍然无法直接监听到该属性的变化。这是因为Vue.set()方法在内部使用了与Object.defineProperty()相同的机制去添加属性,但是Vue.set()只会触发属性值的变化,而不会触发属性的添加。

    4. 嵌套属性的问题:对于嵌套对象属性,当我们添加新的属性时,Vue是无法进行监听的。只有在初始化阶段定义的嵌套属性才会被Vue监听到。

    5. 异步更新问题:如果我们使用Vue的异步更新机制(例如在nextTick中执行属性的赋值操作),则Vue也是无法直接监听到新增的属性。这是因为Vue的异步更新机制会导致视图的更新延迟到下一个事件循环中,而新添加的属性往往会在当前事件循环中被读取到。

    总结起来,Vue2无法直接监听新增属性的原因是因为它只会在初始化时对data中的属性进行监听,对于后续动态添加的属性无法自动进行响应式处理。解决这个问题的方法是使用Vue.set()或者Vue.$set()方法添加属性,或者使用Vue.set()方法更新嵌套对象属性,或者在赋值操作之后手动触发数据更新,例如使用this.$forceUpdate()方法。

    2年前 0条评论
  • fiy的头像
    fiy
    Worktile&PingCode市场小伙伴
    评论

    Vue.js是一个用于构建用户界面的渐进式JavaScript框架。在Vue.js 2.x版本中,当我们给一个已经创建的Vue实例新增一个属性时,Vue实例默认是无法监听到这个新增属性的变化的。这是因为Vue.js在创建实例时会对实例的属性进行劫持,即将属性转化为getter和setter,以便Vue能够追踪属性的变化并进行响应式更新。

    但是在实例创建之后,如果通过以下方式新增属性:

    vm.$set(object, key, value);
    

    其中,vm是Vue实例对象,object是需要新增属性的对象,key是属性名,value是属性值。

    这样,Vue实例就能够监听到新增属性的变化了。下面我们来详细解析一下这个方法的使用和原理。

    $set方法的使用

    可以通过vm.$set方法来给Vue实例的对象新增属性,例如:

    var vm = new Vue({
      data: {
        message: 'Hello Vue!'
      }
    });
    
    vm.$set(vm, 'name', 'Tom');
    

    在上面的例子中,我们给Vue实例vm新增了一个name属性,并赋予其初始值'Tom'。此时,Vue实例会自动追踪这个新增属性的变化。

    $set方法的原理

    vm.$set方法实际上是调用了Vue的全局方法Vue.set,我们也可以直接使用Vue.set来新增属性。

    Vue.set的实现原理是通过调用defineReactive方法将新增属性转化为响应式的getter和setter。defineReactive方法是Vue的响应式系统的核心方法之一。

    当我们给一个对象新增一个属性时,defineReactive方法会为这个新增属性创建一个专属的Dep实例,用于收集依赖和触发更新。同时,它会递归地对这个新增属性进行深度劫持,将其转化为响应式的getter和setter。

    getters 负责依赖收集,也就是将观察者对象添加到订阅者列表中;
    setters 负责派发更新,即当数据发生改变时,触发订阅者列表中所有订阅者的更新方法。

    defineReactive方法的实现大致如下:

    function defineReactive(obj, key, val) {
      // 对值进行递归深度劫持
      observer(val);
      
      // 创建一个Dep对象
      var dep = new Dep();
      
      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter() {
          // 若当前有Dep对象,则进行依赖收集
          if (Dep.target) {
            dep.depend();
          }
          return val;
        },
        set: function reactiveSetter(newVal) {
          if (newVal === val) {
            return;
          }
          val = newVal;
          // 当数据发生改变时,触发订阅者列表更新
          dep.notify();
        }
      });
    }
    

    对于对象属性的深度劫持,defineReactive方法内部会递归调用observer方法,使对象的每个属性都具有响应式的能力。

    综上所述,使用vm.$set方法或Vue.set方法新增属性时,Vue会自动对这个新增属性进行劫持,使其具有响应式的能力,从而能够监听到新增属性的变化。

    2年前 0条评论
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部