返回

前端基础夯实:手写实现Vue 2.x响应式原理

前端

在前端开发领域,响应式编程是至关重要的一个概念,它能帮助开发者在数据发生变化时自动更新UI界面。而Vue 2.x作为一款优秀的MVVM框架,其响应式原理更是值得深入探究和掌握。

本文将带领你一步步手写实现Vue 2.x的响应式原理,让你对响应式编程有一个更透彻的理解。我们从官方文档入手,分析基本原理,再到实践实现,循序渐进,深入浅出。

官方文档释义

Vue.js官网对于响应式原理的解释非常清晰:

Vue.js 的响应式系统是基于JavaScript的Proxy和Object.defineProperty实现的,它劫持了对象的属性访问,从而在属性值发生改变时触发相应的回调函数。

基本原理

基于上面的释义,我们可以将响应式原理的基本步骤拆解为:

  1. 劫持对象属性访问: 通过Object.defineProperty对对象的属性进行劫持,当属性被访问时,会触发相应的getter函数。
  2. 收集依赖: 在getter函数中,收集当前组件所依赖的数据属性,并建立依赖关系。
  3. 触发更新: 当所依赖的数据属性发生改变时,触发其对应的setter函数,执行更新操作。

实践实现

下面我们来手写实现Vue 2.x的响应式原理:

// 1. 创建Observer类
class Observer {
  constructor(data) {
    this.data = data;
    this.deps = [];
    this.walk(data);
  }

  // 2. 遍历对象,对属性进行劫持
  walk(data) {
    for (let key in data) {
      this.defineReactive(data, key);
    }
  }

  // 3. 对属性进行劫持
  defineReactive(data, key) {
    let dep = new Dep();
    let val = data[key];
    Object.defineProperty(data, key, {
      get() {
        dep.addDep(this);
        return val;
      },
      set(newVal) {
        if (val === newVal) return;
        val = newVal;
        dep.notify();
      },
    });
  }
}

// 4. 创建Dep类,管理依赖收集
class Dep {
  constructor() {
    this.subs = [];
  }

  // 5. 添加依赖
  addDep(sub) {
    this.subs.push(sub);
  }

  // 6. 通知依赖更新
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

// 7. 创建Watcher类,管理组件更新
class Watcher {
  constructor(vm, exp, cb) {
    this.vm = vm;
    this.exp = exp;
    this.cb = cb;
    this.update();
  }

  // 8. 更新视图
  update() {
    this.cb.call(this.vm, this.vm.data[this.exp]);
  }
}

// 9. 对传入数据进行响应式化
export default function observable(data) {
  if (typeof data !== "object" || data === null) {
    return data;
  }
  return new Observer(data).data;
}

应用示例

const app = new Vue({
  data() {
    return {
      message: "Hello Vue!",
    };
  },
  render(h) {
    return h("div", {
      innerHTML: this.message,
    });
  },
});

app.$mount("#app");

SEO优化