Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

从零写一个 Vue(三)数组监听 #8

Open
buppt opened this issue Jun 17, 2020 · 0 comments
Open

从零写一个 Vue(三)数组监听 #8

buppt opened this issue Jun 17, 2020 · 0 comments

Comments

@buppt
Copy link
Owner

buppt commented Jun 17, 2020

写在前面

本篇是从零实现vue2系列第三篇,为 YourVue 添加数组监听。

文章会最先更新在公众号:BUPPT。代码仓库:https://github.com/buppt/YourVue

正文

上一篇我们实现了双向绑定,篇幅原因没有处理数组。我们知道 vue 是通过重写了几个数组的方法实现的数组监听,先在 Observer 中添加几行代码。

class Observer{
    constructor(value) {
        this.value = value
        this.dep = new Dep()
        def(value, '__ob__', this)
        if(Array.isArray(value)){
            value.__proto__ = arrayMethods
            this.observeArray(value)
        }else{
            this.walk(value);
        }
    }
    observeArray(value){
        value.forEach(item => {
            observe(item)
        })
    }
}

首先把 observer 实例赋值给__ob__参数,以便后用。

修改数组的__proto__只向一个新的原型,下面看一下新的原型 arrayMethods。

const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
methodsToPatch.forEach(function (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)
    ob.dep.notify()
    return result
  })
})

可以发现 Vue 对 push、pop、shift、unshift、splice、sort、reverse 七个方法进行了拓展,执行这七个方法的时候会触发 dep.notify(),就是上一篇中的执行所有订阅 watcher 的更新函数。如果是 push、unshift 和 splice 还会对增加到数组中的数据进行 observe。

代码没有直接修改 Array.prototype,而是将 arrayMenthods 赋值给被观测数组的 __proto__,这样不会污染全局 Array。

这样我们就可以在 main.js 中定义一个数组,调用 push、pop 等方法,也会触发更新。

new YourVue({
  el: '#app',
  data: {
      count: 0,
      message: 'message',
      items: [1,2,3,0,5]
  },
  template: `
      <div>
          array: {{items}}
          <div>{{count}}</div>
          <button @click="addCount">addCount</button>
          <h4>{{message}}</h4>
          <button @click="decCount">decCount</button>
      </div>
  `,
  methods:{
    addCount(){
        this.count += 1
        this.items.push(this.count)
    },
    decCount(){
        this.count -= 1
        this.items.pop()
    }
  }
})

本篇代码:https://github.com/buppt/YourVue/tree/master/oldSrc/3.array_observe

至此双向绑定就已经完成啦,下篇实现虚拟 dom。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant