当前位置:首页 > 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 的局限性:

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 实现双向绑定的原理 Vue 的双向绑定是通过数据劫持结合发布者-订阅者模式实现的,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。以下是具…

vue实现双向

vue实现双向

Vue 实现双向绑定的方法 Vue 的双向绑定主要通过 v-model 指令实现,它结合了数据绑定和事件监听,适用于表单元素(如 input、select、textarea 等)。以下是几种常见的实现…

vue双向实现数据

vue双向实现数据

Vue 双向数据绑定的实现原理 Vue 的双向数据绑定主要通过 v-model 指令实现,其核心是结合了数据劫持(Object.defineProperty 或 Proxy)和发布-订阅模式。以下是具…

vue实现绑定herf

vue实现绑定herf

Vue 中实现绑定 href 的方法 在 Vue 中绑定 href 属性可以通过多种方式实现,以下是几种常见的方法: 使用 v-bind 或简写 : 通过 v-bind 或简写 : 动态绑定 hr…

vue 数据绑定实现

vue 数据绑定实现

Vue 数据绑定的实现方式 Vue 的数据绑定主要通过响应式系统和模板语法实现,以下是核心方法: 双向数据绑定(v-model) 通过 v-model 指令实现表单元素与数据的双向绑定,自动同步数据…

vue实现双向绑定

vue实现双向绑定

Vue 双向绑定的实现原理 Vue 的双向绑定是通过 v-model 指令实现的,其本质是语法糖,结合了 v-bind(属性绑定)和 v-on(事件监听)。以下是具体实现方式: 使用 v-model…