美文网首页让前端飞
Vue不能观察到数组length的变化

Vue不能观察到数组length的变化

作者: 88b61f4ab233 | 来源:发表于2018-11-23 22:19 被阅读5次

    由于 JavaScript 的限制,Vue 不能检测以下变动的数组: 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength

    因为vue的响应式是通过 Object.defineProperty 来实现的,但是数组的length属性是不能添加getter和setter,所有无法通过观察length来判断。

    为什么Vue不能观察到数组length的变化

    如下代码,虽然看起来数组的length是10,但是for in的时候只能遍历出0, 1, 2,导致了只有前三个索引被加上了getter 和setter

    var a = [0, 1, 2]
    a.length = 10
    // 只是显示的给length赋值,索引3-9的对应的value也会赋值undefined
    // 但是索引3-9的key都是没有值的
    // 我们可以用for-in打印,只会打印0,1,2
    for (var key in a) {
     console.log(key) // 0,1,2
    }
    //前端全栈学习交流圈:866109386
    //面向1-3经验年前端开发人员
    //帮助突破技术瓶颈,提升思维能力
    

    那么vue提供了一些解决方法

    使用内置的Vue.$set

    让数组显式的进行某个索引的观察 Vue.set(array, indexOfItem, newValue)

    实际上是调用了

    Object.defineProperty(array, indexOfItem, {
     enumerable: true,
     configurable: true,
     get() { },
     set(newVal) { }
    })
    //前端全栈学习交流圈:866109386
    //面向1-3经验年前端开发人员
    //帮助突破技术瓶颈,提升思维能力
    

    这样可以手动指定需要观察的key,那么就可以达到预期的效果。

    重写了 push, pop, shift, unshift, splice, sort, reverse方法

    Vue源码

    const arrayProto = Array.prototype
    export const arrayMethods = Object.create(arrayProto)
     
    /**
     * Intercept mutating methods and emit events
     */
    ;[
     'push',
     'pop',
     'shift',
     'unshift',
     'splice',
     'sort',
     'reverse'
    ]
    .forEach(function (method) {
     // cache original method
     const original = arrayProto[method]
     def(arrayMethods, method, function mutator (...args) {
      const result = original.apply(this, args)
      const ob = this.__ob__
      let inserted
      switch (method) {
       case 'push':
       case 'unshift':
        inserted = args
        break
       case 'splice':
        inserted = args.slice(2)
        break
      }
      if (inserted) ob.observeArray(inserted)
      // notify change
      ob.dep.notify()
      return result
     })
    })
    

    这些是在Array.proto上 进行了方法重写或者添加

    并且对添加属性的方法如 push,unshift,splice 所添加进来的新属性进行手动观察,源码为

    if (inserted) ob.observeArray(inserted)
    

    对以上方法进行了手动的进行消息触发

    ob.dep.notify()
    

    结论

    vue对数组的length直接改变无法直接进行观察,提供了vue.$set 进行显式观察,并且重写了 push, pop, shift, unshift, splice, sort, reverse方法来进行隐式观察。

    相关文章

      网友评论

        本文标题:Vue不能观察到数组length的变化

        本文链接:https://www.haomeiwen.com/subject/jzbsqqtx.html