当前位置:首页 > VUE

自己实现vue双括号

2026-02-24 04:08:01VUE

实现 Vue 双括号插值的基本原理

Vue 的双括号插值({{}})是一种数据绑定的语法,核心是通过解析模板中的双括号内容,将其替换为对应数据对象的属性值,并实现数据变化时的自动更新。

核心步骤

数据劫持与响应式 通过 Object.definePropertyProxy 监听数据对象属性的变化。当数据被访问或修改时,触发相应的 getter/setter。

自己实现vue双括号

function observe(data) {
  if (!data || typeof data !== 'object') return;
  Object.keys(data).forEach(key => {
    let value = data[key];
    const dep = new Dep();
    observe(value);
    Object.defineProperty(data, key, {
      get() {
        Dep.target && dep.addSub(Dep.target);
        return value;
      },
      set(newVal) {
        if (newVal === value) return;
        value = newVal;
        observe(newVal);
        dep.notify();
      }
    });
  });
}

依赖收集与发布订阅 定义一个 Dep 类管理依赖(Watcher),并在数据变化时通知所有订阅者更新。

自己实现vue双括号

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

模板编译 解析 HTML 模板,提取双括号中的表达式,并创建对应的 Watcher 实例。

function compile(el, vm) {
  vm.$el = document.querySelector(el);
  const fragment = document.createDocumentFragment();
  let child;
  while (child = vm.$el.firstChild) {
    fragment.appendChild(child);
  }
  replace(fragment, vm);
  vm.$el.appendChild(fragment);
}

function replace(node, vm) {
  const reg = /\{\{(.*?)\}\}/g;
  if (node.nodeType === 3) {
    const text = node.textContent;
    if (reg.test(text)) {
      const exp = RegExp.$1.trim();
      node.textContent = text.replace(reg, vm[exp]);
      new Watcher(vm, exp, val => {
        node.textContent = text.replace(reg, val);
      });
    }
  }
  if (node.nodeType === 1) {
    Array.from(node.childNodes).forEach(child => replace(child, vm));
  }
}

Watcher 实现 Watcher 作为观察者,在初始化时触发 getter 收集依赖,并在数据更新时执行回调。

class Watcher {
  constructor(vm, exp, cb) {
    this.vm = vm;
    this.exp = exp;
    this.cb = cb;
    Dep.target = this;
    this.value = vm[exp]; // 触发 getter
    Dep.target = null;
  }
  update() {
    const newVal = this.vm[this.exp];
    if (newVal !== this.value) {
      this.value = newVal;
      this.cb(newVal);
    }
  }
}

完整示例

class MiniVue {
  constructor(options) {
    this.$options = options;
    this.$data = options.data;
    observe(this.$data);
    compile(options.el, this);
    proxy(this, '$data');
  }
}

function proxy(vm, sourceKey) {
  Object.keys(vm[sourceKey]).forEach(key => {
    Object.defineProperty(vm, key, {
      get() {
        return vm[sourceKey][key];
      },
      set(newVal) {
        vm[sourceKey][key] = newVal;
      }
    });
  });
}

// 使用示例
const vm = new MiniVue({
  el: '#app',
  data: { message: 'Hello Vue!' }
});

关键点说明

  • 数据劫持通过 Object.defineProperty 实现,Vue 3 改用 Proxy
  • 模板编译通过递归遍历 DOM 节点,匹配双括号内容。
  • 依赖收集在 getter 中完成,更新通知在 setter 中触发。
  • Watcher 是连接数据和视图的桥梁,负责更新 DOM。

标签: 括号vue
分享给朋友:

相关文章

vue实现switch

vue实现switch

Vue 实现 Switch 开关组件 在 Vue 中实现 Switch 开关组件可以通过自定义组件或使用现有 UI 库完成。以下是几种常见实现方式: 自定义 Switch 组件 创建一个基础 Sw…

vue实现分栏

vue实现分栏

Vue实现分栏的常见方法 使用CSS Flexbox布局 通过Flexbox可以快速实现分栏效果,适合大多数响应式布局场景 <template> <div class="con…

vue实现treeview

vue实现treeview

Vue 实现 TreeView 的方法 使用递归组件实现 TreeView 递归组件是 Vue 中实现 TreeView 的常见方式。通过组件调用自身,可以轻松处理嵌套的树形结构数据。 <te…

vue 实现音乐

vue 实现音乐

Vue 实现音乐播放功能 在 Vue 中实现音乐播放功能,可以通过 HTML5 的 <audio> 元素或第三方库如 howler.js 来实现。以下是两种方法的详细步骤: 使用 HTM…

vue实现侧导航

vue实现侧导航

Vue 实现侧边导航 使用 Vue 实现侧边导航可以通过多种方式完成,以下是一种常见的实现方法,结合 Vue Router 和动态组件。 基础结构 创建侧边导航栏的基本结构,通常使用 <ul&…

vue实现选择置顶

vue实现选择置顶

Vue 实现选择置顶功能 在 Vue 中实现选择置顶功能,可以通过操作数据数组或结合 CSS 样式来实现。以下是几种常见的实现方法: 数组排序法 通过操作数据数组,将被选中的项移动到数组首位: /…