374632897 / blog

前端小虾蟹的个人博客
7 stars 1 forks source link

Vue #24

Open 374632897 opened 7 years ago

374632897 commented 7 years ago

Vue 的 Observer

可以在Vue 官方文档看到对于响应式的描述。

数组

监测范围:数组的push,pop,shift,unshift,splice,sort,reverse操作。 具体代码:

// core/observer/array.js
import { def } from '../util/index'

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
  })
})

通过Object.create(Array.prototype), 得到一个从数组构造函数的原型对象上继承后的对象, 然后对这个继承后的构造函数的指定方法进行重新定义。

// core/observer/index.js
export class Observer {
  constructor (value: any) {
    this.value = value
    this.dep = new Dep()
    this.vmCount = 0
    def(value, '__ob__', this)
    if (Array.isArray(value)) {
      const augment = hasProto
        ? protoAugment
        : copyAugment
      augment(value, arrayMethods, arrayKeys)
      this.observeArray(value)
    } else {
      this.walk(value)
    }
  }
}
function protoAugment (target, src: Object, keys: any) {
  target.__proto__ = src
}

这里最重要的就是 protoAugment 方法, 它的作用是重写一个实例的 __proto__属性。 在监听数组的时候, 默认情况下数组的__proto__也就是Array.prototype, 在这个函数内部将它的__proto__属性指向了继承自Array.prototype并且添加了监听后的ArrayMethods对象, 这样通过相应的方法来操作数组的时候, 就会触发其监听了。

对象

监测范围: 非添加删除操作。 这个也就是通过 defineProperty 来定义的。

pengchangjiang commented 6 years ago

工程中遇到一个问题,问题是这样的,

组件结构 A(父) B(子) C(孙) 层级描述 变量mapstyle({layers:[{},{},{}],···})存在vuex中,在B里取vuex中mapstyle中layers v-for 渲染组件C, 数据变化 在A中改变mapstyle.layers,使用push时组件C能正确渲染,使用splice增加组件C不能渲染不正确。两种情况组件B渲染都是正确的,同时组件C里断点只进去了一次,取的是layers中最后一个数据进行渲染。

pengchangjiang commented 6 years ago

求解答呀,多谢多谢

374632897 commented 6 years ago

@pengchangjiang 我已经没用 Vue 很久了哈, 你在使用这两种方法改变后, 在 Vuex 的 store 里面对应的数据是一样的吗?

pengchangjiang commented 6 years ago

vuex store里面的值是一样的