当前位置:首页 > VUE

vue双向绑定实现简单

2026-02-09 17:29:43VUE

Vue 双向绑定的实现原理

Vue 的双向绑定是通过数据劫持结合发布者-订阅者模式实现的,主要依赖 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)来监听数据变化。

vue双向绑定实现简单

使用 Object.defineProperty 实现

Vue 2.x 使用 Object.defineProperty 劫持对象的属性,通过 getter 和 setter 实现数据监听。

vue双向绑定实现简单

function defineReactive(obj, key, val) {
  const dep = new Dep(); // 依赖收集器

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      if (Dep.target) {
        dep.addSub(Dep.target); // 收集依赖
      }
      return val;
    },
    set(newVal) {
      if (newVal === val) return;
      val = newVal;
      dep.notify(); // 通知更新
    }
  });
}

class Dep {
  constructor() {
    this.subs = [];
  }
  addSub(sub) {
    this.subs.push(sub);
  }
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

Dep.target = null;

使用 Proxy 实现

Vue 3.x 改用 Proxy 实现数据劫持,可以监听整个对象而无需递归遍历。

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key); // 收集依赖
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      Reflect.set(target, key, value, receiver);
      trigger(target, key); // 触发更新
      return true;
    }
  });
}

const targetMap = new WeakMap();

function track(target, key) {
  if (!Dep.target) return;
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  dep.add(Dep.target);
}

function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const dep = depsMap.get(key);
  if (dep) {
    dep.forEach(effect => effect());
  }
}

实现简单的双向绑定

结合 v-model 指令,可以实现一个简单的双向绑定示例。

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

<script>
  function compile(el, vm) {
    el.querySelectorAll('[v-model]').forEach(node => {
      const key = node.getAttribute('v-model');
      node.value = vm.data[key];
      node.addEventListener('input', () => {
        vm.data[key] = node.value;
      });
    });

    el.querySelectorAll('*').forEach(node => {
      if (node.textContent.includes('{{')) {
        const key = node.textContent.match(/\{\{(.*?)\}\}/)[1].trim();
        node.textContent = vm.data[key];
        new Watcher(vm, key, val => {
          node.textContent = val;
        });
      }
    });
  }

  class Vue {
    constructor(options) {
      this.data = options.data;
      observe(this.data);
      compile(options.el, this);
    }
  }

  const vm = new Vue({
    el: document.getElementById('app'),
    data: { message: 'Hello Vue!' }
  });
</script>

关键点总结

  • 数据劫持:通过 Object.definePropertyProxy 监听数据变化。
  • 依赖收集:在 getter 中收集依赖,在 setter 中触发更新。
  • 模板编译:解析模板中的指令和插值表达式,建立数据与视图的关联。
  • 更新机制:数据变化时通知所有依赖的视图更新。

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

相关文章

jquery事件绑定

jquery事件绑定

jQuery 事件绑定的基本方法 使用 on() 方法绑定事件是最推荐的方式,兼容性强且支持动态元素。语法如下: $(selector).on(eventName, handlerFunction)…

vue如何实现绑定

vue如何实现绑定

数据绑定基础 Vue 通过 v-bind 指令实现动态绑定 HTML 属性或组件 prop。基本语法为 v-bind:属性名="表达式",简写为 :属性名="表达式"。例如绑定 class 或 sty…

实现vue数组双向绑定

实现vue数组双向绑定

Vue 数组双向绑定的实现方法 Vue 通过数据劫持和发布-订阅模式实现数据的双向绑定,但直接修改数组的某些方法(如索引赋值)无法触发视图更新。以下是实现数组双向绑定的几种方法: 使用 Vue.se…

vue实现数组元素绑定

vue实现数组元素绑定

Vue 数组元素绑定方法 在 Vue 中实现数组元素绑定需要特别注意响应式更新的问题。以下是几种常见实现方式: 直接索引绑定(不推荐) 直接通过索引修改数组元素不会触发视图更新: this.arr…

vue实现动态绑定样式

vue实现动态绑定样式

动态绑定样式的方法 在Vue中实现动态绑定样式主要通过v-bind:class和v-bind:style指令完成,支持对象语法、数组语法等多种灵活方式。 对象语法 通过对象可以动态切换class,对…

vue自己实现双向绑定

vue自己实现双向绑定

实现 Vue 双向绑定的核心原理 双向绑定的核心是通过数据劫持结合发布-订阅模式实现的。主要涉及 Object.defineProperty 或 Proxy 来监听数据变化,并通过观察者模式通知视图更…