当前位置:首页 > VUE

模拟vue实现原理

2026-02-19 21:52:24VUE

模拟 Vue 实现原理

Vue.js 的核心原理包括数据响应式、虚拟 DOM、模板编译等。以下是一个简化版的模拟实现,重点展示数据响应式和虚拟 DOM 的基本概念。

数据响应式实现

通过 Object.definePropertyProxy 实现数据劫持,监听数据变化并触发更新。

模拟vue实现原理

class Observer {
  constructor(data) {
    this.walk(data);
  }

  walk(data) {
    if (!data || typeof data !== 'object') return;
    Object.keys(data).forEach(key => {
      this.defineReactive(data, key, data[key]);
    });
  }

  defineReactive(obj, key, val) {
    const dep = new Dep();
    this.walk(val); // 递归处理嵌套对象
    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;
        dep.notify(); // 通知所有订阅者更新
      }
    });
  }
}

class Dep {
  constructor() {
    this.subs = [];
  }

  addSub(sub) {
    this.subs.push(sub);
  }

  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

Dep.target = null; // 全局唯一 Watcher

虚拟 DOM 与 Diff 算法

虚拟 DOM 是一个轻量级的 JavaScript 对象,描述真实 DOM 结构。Diff 算法用于高效更新 DOM。

模拟vue实现原理

class VNode {
  constructor(tag, data, children, text) {
    this.tag = tag;
    this.data = data;
    this.children = children;
    this.text = text;
  }
}

function createElement(tag, data, children) {
  return new VNode(tag, data, children, undefined);
}

function createTextNode(text) {
  return new VNode(undefined, undefined, undefined, text);
}

function patch(oldVnode, vnode) {
  if (!oldVnode) {
    // 首次渲染
    return createElm(vnode);
  } else {
    // Diff 更新
    if (oldVnode.tag === vnode.tag) {
      const el = (vnode.el = oldVnode.el);
      updateProps(el, oldVnode.data, vnode.data);
      updateChildren(el, oldVnode.children, vnode.children);
    } else {
      // 替换节点
      const parentEl = oldVnode.el.parentNode;
      parentEl.removeChild(oldVnode.el);
      parentEl.appendChild(createElm(vnode));
    }
  }
}

function createElm(vnode) {
  if (vnode.text) {
    return document.createTextNode(vnode.text);
  }
  const el = document.createElement(vnode.tag);
  updateProps(el, {}, vnode.data);
  vnode.children.forEach(child => {
    el.appendChild(createElm(child));
  });
  vnode.el = el;
  return el;
}

模板编译

将模板字符串转换为渲染函数,通常涉及解析、优化和代码生成三个阶段。

function compile(template) {
  const ast = parse(template); // 解析为 AST
  optimize(ast); // 静态节点标记
  const code = generate(ast); // 生成渲染函数代码
  return new Function(`with(this){return ${code}}`);
}

// 示例:简单插值解析
function parse(template) {
  const tokens = template.split(/(\{\{\w+\}\})/);
  const children = [];
  tokens.forEach(token => {
    if (token.match(/\{\{\w+\}\}/)) {
      const key = token.slice(2, -2);
      children.push({
        type: 'interpolation',
        key
      });
    } else if (token.trim()) {
      children.push({
        type: 'text',
        value: token
      });
    }
  });
  return { children };
}

整合 Watcher 与更新机制

Watcher 作为观察者,连接响应式数据和视图更新。

class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm;
    this.getter = parsePath(expOrFn);
    this.cb = cb;
    this.value = this.get();
  }

  get() {
    Dep.target = this;
    const value = this.getter.call(this.vm, this.vm);
    Dep.target = null;
    return value;
  }

  update() {
    const oldValue = this.value;
    this.value = this.get();
    this.cb.call(this.vm, this.value, oldValue);
  }
}

function parsePath(path) {
  const segments = path.split('.');
  return function(obj) {
    for (let i = 0; i < segments.length; i++) {
      if (!obj) return;
      obj = obj[segments[i]];
    }
    return obj;
  };
}

完整流程示例

class MiniVue {
  constructor(options) {
    this.$options = options;
    this._data = options.data;
    new Observer(this._data);
    this._proxyData();
    this.$compile = compile(options.template);
    new Watcher(this, 'render', this._update.bind(this));
  }

  _proxyData() {
    Object.keys(this._data).forEach(key => {
      Object.defineProperty(this, key, {
        get() {
          return this._data[key];
        },
        set(newVal) {
          this._data[key] = newVal;
        }
      });
    });
  }

  render() {
    return this.$compile.call(this);
  }

  _update() {
    const vnode = this.render();
    patch(this._vnode, vnode);
    this._vnode = vnode;
  }
}

以上代码展示了 Vue 核心原理的简化实现,实际 Vue 源码更为复杂,包含更多优化和边界处理。

标签: 原理vue
分享给朋友:

相关文章

vue实现组件循环

vue实现组件循环

Vue 组件循环的实现方法 在 Vue 中实现组件循环通常使用 v-for 指令,可以循环渲染数组或对象的数据到组件上。 基本数组循环 通过 v-for 指令遍历数组,渲染多个相同结构的组件。…

vue插槽实现

vue插槽实现

插槽的基本概念 Vue插槽(Slot)是一种内容分发机制,允许父组件向子组件传递模板片段,子组件通过<slot>标签定义接收位置。插槽的核心作用是增强组件的灵活性和复用性。 默认插槽…

vue实现模块

vue实现模块

Vue 实现模块化的方法 Vue 支持多种模块化开发方式,可以根据项目需求选择适合的方案。 使用单文件组件(SFC) 单文件组件是 Vue 最常用的模块化方式,将模板、脚本和样式封装在一个 .vue…

vue实现ajax

vue实现ajax

Vue 中实现 AJAX 的几种方法 在 Vue 中实现 AJAX 请求可以通过原生 JavaScript 的 XMLHttpRequest、第三方库如 axios 或 fetch API 来完成。以…

vue实现 单选

vue实现 单选

实现 Vue 单选功能 在 Vue 中实现单选功能可以通过多种方式完成,以下是几种常见的方法: 使用 v-model 绑定单选按钮 通过 v-model 可以轻松实现单选功能,将单选按钮的值绑定到同…

vue实现选择

vue实现选择

Vue 实现选择功能的方法 在 Vue 中实现选择功能可以通过多种方式完成,以下介绍几种常见的实现方法。 使用 v-model 绑定单选 通过 v-model 可以轻松实现单选功能。以下是一个简单…