当前位置:首页 > VUE

vue实现双向绑定模拟

2026-01-21 12:51:39VUE

Vue 双向绑定模拟实现

Vue 的双向绑定核心是通过数据劫持结合发布-订阅模式实现。以下是一个简化版的模拟实现:

数据劫持(Object.defineProperty)

通过 Object.defineProperty 劫持对象的属性,在属性被访问或修改时触发 getter 和 setter:

function observe(data) {
  if (!data || typeof data !== 'object') return;
  Object.keys(data).forEach(key => {
    defineReactive(data, key, data[key]);
  });
}

function defineReactive(obj, key, val) {
  observe(val); // 递归劫持嵌套对象
  const dep = new Dep(); // 每个属性对应一个 Dep 实例

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      Dep.target && dep.addSub(Dep.target); // 收集依赖
      return val;
    },
    set(newVal) {
      if (newVal === val) return;
      val = newVal;
      observe(newVal); // 新值是对象时继续劫持
      dep.notify(); // 通知更新
    }
  });
}

依赖收集(Dep 类)

class Dep {
  constructor() {
    this.subs = [];
  }
  addSub(sub) {
    this.subs.push(sub);
  }
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}
Dep.target = null; // 静态属性指向当前 Watcher

观察者(Watcher 类)

class Watcher {
  constructor(vm, exp, cb) {
    this.vm = vm;
    this.exp = exp;
    this.cb = cb;
    this.value = this.get(); // 触发依赖收集
  }
  get() {
    Dep.target = this;
    const value = this.vm._data[this.exp]; // 触发 getter
    Dep.target = null;
    return value;
  }
  update() {
    const newValue = this.vm._data[this.exp];
    if (newValue !== this.value) {
      this.value = newValue;
      this.cb.call(this.vm, newValue);
    }
  }
}

编译器(Compile)

简化版模板编译,处理 v-model 指令:

function compile(node, vm) {
  if (node.nodeType === 1) { // 元素节点
    const attrs = node.attributes;
    Array.from(attrs).forEach(attr => {
      if (attr.name === 'v-model') {
        const exp = attr.value;
        node.value = vm._data[exp];
        new Watcher(vm, exp, value => {
          node.value = value;
        });
        node.addEventListener('input', e => {
          vm._data[exp] = e.target.value;
        });
      }
    });
  }
}

完整示例

<div id="app">
  <input v-model="message">
  <p>{{ message }}</p>
</div>

<script>
class Vue {
  constructor(options) {
    this._data = options.data;
    observe(this._data);
    compile(document.querySelector(options.el), this);
  }
}

new Vue({
  el: '#app',
  data: { message: 'Hello Vue' }
});
</script>

Proxy 实现方案(Vue 3)

Vue 3 改用 Proxy 实现响应式,解决了 Object.defineProperty 的局限性:

vue实现双向绑定模拟

function reactive(data) {
  if (typeof data !== 'object') return data;
  const observed = new Proxy(data, {
    get(target, key) {
      track(target, key); // 依赖收集
      return Reflect.get(target, key);
    },
    set(target, key, value) {
      const result = Reflect.set(target, key, value);
      trigger(target, key); // 触发更新
      return result;
    }
  });
  Object.keys(data).forEach(key => {
    observed[key] = reactive(data[key]); // 递归处理
  });
  return observed;
}

关键点说明

  • 数据劫持:通过拦截对象属性的访问和修改实现响应式
  • 依赖收集:在 getter 中收集依赖,setter 中通知更新
  • 发布-订阅模式:Dep 作为调度中心,Watcher 作为订阅者
  • 批量异步更新:实际实现中会使用 nextTick 进行异步更新优化

标签: 绑定双向
分享给朋友:

相关文章

实现vue双向绑定

实现vue双向绑定

Vue双向绑定的实现原理 Vue的双向绑定主要通过数据劫持结合发布-订阅模式实现。核心是利用Object.defineProperty()或ES6的Proxy来劫持各个属性的getter和setter…

react如何绑定事件

react如何绑定事件

React 事件绑定方法 在 React 中绑定事件有多种方式,以下是常见的几种方法: 使用 onClick 或其他事件属性直接绑定 <button onClick={() => co…

vue实现事件绑定

vue实现事件绑定

Vue 事件绑定实现方法 Vue 提供了多种方式实现事件绑定,以下是常用方法: v-on 指令 使用 v-on 指令绑定事件监听器,语法为 v-on:event="handler" 或简写为 @ev…

实现vue数据绑定

实现vue数据绑定

Vue数据绑定的实现方式 Vue.js通过数据劫持和发布-订阅模式实现数据绑定,核心是响应式系统。以下是主要实现方法: 双向数据绑定(v-model) <input v-model="mess…

vue双向数据怎么实现

vue双向数据怎么实现

Vue 双向数据绑定的实现 Vue 的双向数据绑定主要通过 v-model 指令实现,结合数据劫持(Object.defineProperty 或 Proxy)和发布-订阅模式完成数据与视图的同步更新…