当前位置:首页 > VUE

自己实现vue双括号

2026-01-23 13:31:27VUE

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

Vue 的双括号插值({{ }})是数据绑定的核心功能之一,其本质是将模板中的表达式解析并与数据对象动态关联。以下是手动实现类似功能的步骤:

数据劫持与响应式

通过 Object.definePropertyProxy 实现数据劫持,监听数据变化:

自己实现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) {
          value = newVal;
          observe(newVal); // 新值也可能是对象
          dep.notify(); // 触发更新
        }
      }
    });
  });
}

依赖收集与发布订阅

实现一个简单的发布订阅模式来管理依赖:

自己实现vue双括号

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

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

模板解析与编译

通过正则匹配 {{ }} 并替换为数据:

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

  const regex = /\{\{(.*?)\}\}/g;
  function replaceText(node) {
    if (node.nodeType === 3) { // 文本节点
      const text = node.textContent;
      if (regex.test(text)) {
        const key = RegExp.$1.trim();
        new Watcher(vm, key, val => {
          node.textContent = text.replace(regex, val);
        });
        node.textContent = text.replace(regex, vm[key]);
      }
    }
    if (node.childNodes) {
      node.childNodes.forEach(replaceText);
    }
  }
  replaceText(fragment);
  el.appendChild(fragment);
}

初始化实例

整合以上逻辑到主类中:

class MiniVue {
  constructor(options) {
    this.$data = options.data();
    observe(this.$data);
    this.proxyData();
    compile(options.el, this);
  }
  proxyData() {
    Object.keys(this.$data).forEach(key => {
      Object.defineProperty(this, key, {
        get() {
          return this.$data[key];
        },
        set(val) {
          this.$data[key] = val;
        }
      });
    });
  }
}

使用示例

<div id="app">{{ message }}</div>
<script>
  new MiniVue({
    el: document.getElementById('app'),
    data: () => ({ message: 'Hello World' })
  });
</script>

关键点说明

  • 数据劫持:通过 Object.defineProperty 拦截属性的读写操作。
  • 依赖收集:在 getter 中收集依赖(Watcher),在 setter 中触发更新。
  • 模板编译:递归遍历 DOM 节点,替换 {{ }} 为实际数据并建立绑定。
  • 性能优化:实际 Vue 还包含虚拟 DOM、异步更新队列等机制,此处仅展示核心原理。

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

相关文章

vue实现标签

vue实现标签

Vue 实现标签的方法 在 Vue 中实现标签功能可以通过多种方式完成,以下是几种常见的方法: 使用动态组件 动态组件可以根据不同的条件渲染不同的标签内容。通过 :is 属性动态绑定组件名,实现标签…

vue实现日历

vue实现日历

Vue 实现日历的基本方法 使用 Vue 实现日历可以通过自定义组件或借助第三方库完成。以下是两种常见实现方式: 自定义日历组件 创建基于 Vue 的日历组件需要处理日期计算和渲染逻辑。核心是生成当…

vue 菜单实现

vue 菜单实现

Vue 菜单实现方法 在Vue中实现菜单功能可以通过多种方式完成,以下是几种常见的实现方法: 使用v-for动态生成菜单 通过数据驱动的方式动态渲染菜单项,适合菜单内容可能变化的场景: <t…

vue实现搜索查询

vue实现搜索查询

Vue 实现搜索查询的方法 双向绑定实现实时搜索 在Vue中可以通过v-model绑定输入框的值,结合计算属性或watch监听输入变化实现实时搜索。 <template> <i…

用vue实现滚动

用vue实现滚动

实现滚动的基本方法 在Vue中实现滚动可以通过多种方式完成,包括使用原生JavaScript、Vue指令或第三方库。以下是几种常见的方法: 使用ref和原生JavaScript 在模板中定义一个可滚…

vue实现页面定位

vue实现页面定位

Vue 实现页面定位的方法 在 Vue 中实现页面定位通常可以通过以下几种方式完成,包括使用原生 JavaScript 的 scrollIntoView 方法、Vue Router 的滚动行为配置,以…