当前位置:首页 > 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实现下拉框删除

vue实现下拉框删除

Vue 实现下拉框删除功能 在Vue中实现下拉框的删除功能通常涉及以下步骤: 数据绑定与渲染 在Vue组件中定义数据数组用于存储下拉框选项: data() { return { op…

vue请求实现进度条

vue请求实现进度条

实现请求进度条的方法 在Vue中实现请求进度条可以通过多种方式完成,常见的有使用第三方库如axios结合nprogress或自定义进度条组件。以下是几种实现方法: 使用axios和nprogres…

vue实现文字

vue实现文字

Vue 中实现文字显示的方法 在 Vue 中实现文字显示可以通过多种方式,包括插值表达式、指令、组件等。以下是几种常见的实现方法: 插值表达式 使用双大括号 {{ }} 进行文本插值,这是 Vue…

vue compile 实现

vue compile 实现

Vue 编译实现原理 Vue 的编译过程将模板字符串转换为渲染函数,主要分为解析、优化和代码生成三个阶段。 解析阶段(Parse) 将模板字符串转换为抽象语法树(AST)。Vue 使用正则表达式和…

vue 实现单选

vue 实现单选

使用 v-model 绑定单选值 在 Vue 中,可以通过 v-model 绑定单选按钮的值。定义一个响应式数据(如 selectedOption),并将其与单选按钮的 value 属性关联。…

vue实现试卷

vue实现试卷

Vue实现试卷系统的基本思路 使用Vue.js构建试卷系统需要结合组件化开发、状态管理和后端数据交互。核心功能包括题目展示、答题逻辑、计时器和提交答案。 核心功能模块划分 试卷组件结构 试卷容…