返回

从零入门剖析 Vue 响应式,90 行代码带你玩转数据绑定!

前端

九十行代码手摸手带你透彻理解 Vue 响应式

在现代 Web 开发中,响应式数据绑定是一个非常重要的特性。它允许开发人员轻松地将数据与 UI 绑定在一起,从而实现数据的自动更新。Vue.js 是一个非常流行的前端框架,它内置了强大的响应式系统。在本文中,我们将通过不到 100 行代码,实现一个极小的响应式 Vue。在此过程中,希望读者能了解到 Vue 实例、响应式数据、watcher、dep 四者之间的关系;dep 何时、如何收集 watcher。

核心概念

Vue 实例

Vue 实例是 Vue 应用的核心。它负责管理数据、模板和视图。

响应式数据

响应式数据是 Vue 实例中的数据。当响应式数据发生变化时,Vue 会自动更新视图。

Watcher

Watcher 是 Vue 用来跟踪响应式数据变化的工具。当响应式数据发生变化时,Watcher 会触发对应的回调函数。

Dep

Dep 是 Vue 用来管理 Watcher 的工具。每个响应式数据都对应一个 Dep。当响应式数据发生变化时,Dep 会通知所有 Watcher。

实现一个极小的响应式 Vue

现在,我们来实现一个极小的响应式 Vue。

class Vue {
  constructor(options) {
    this.$data = options.data;
    this.observe(this.$data);
  }

  observe(data) {
    Object.keys(data).forEach(key => {
      this.defineReactive(data, key, data[key]);
    });
  }

  defineReactive(data, key, val) {
    const dep = new Dep();
    Object.defineProperty(data, key, {
      get() {
        dep.addWatcher(Dep.target);
        return val;
      },
      set(newVal) {
        if (val === newVal) return;
        val = newVal;
        dep.notify();
      }
    });
  }
}

class Dep {
  constructor() {
    this.watchers = [];
  }

  addWatcher(watcher) {
    this.watchers.push(watcher);
  }

  notify() {
    this.watchers.forEach(watcher => watcher.update());
  }
}

class Watcher {
  constructor(vm, expr, cb) {
    this.vm = vm;
    this.expr = expr;
    this.cb = cb;
    Dep.target = this;
    this.oldValue = this.get();
  }

  get() {
    return this.vm.$data[this.expr];
  }

  update() {
    const newValue = this.get();
    if (newValue !== this.oldValue) {
      this.cb(newValue, this.oldValue);
    }
  }
}

const vm = new Vue({
  data: {
    count: 0
  }
});

vm.$watch('count', (newVal, oldVal) => {
  console.log(`count changed from ${oldVal} to ${newVal}`);
});

vm.$data.count++;

这个极小的响应式 Vue 可以实现基本的数据绑定功能。当 vm.$data.count 发生变化时,vm.$watch('count', ...) 中的回调函数会被触发。

总结

在这篇文章中,我们通过不到 100 行代码,实现了一个极小的响应式 Vue。在此过程中,希望读者能了解到 Vue 实例、响应式数据、watcher、dep 四者之间的关系;dep 何时、如何收集 watcher。