当前位置:首页 > VUE

从0实现vue

2026-01-15 04:23:54VUE

实现 Vue 的核心功能

Vue 的核心功能包括数据响应式、虚拟 DOM、模板编译等。以下是从零实现 Vue 的基本步骤。

数据响应式系统

数据响应式是 Vue 的核心特性之一,通过 Object.definePropertyProxy 实现数据劫持。以下是基于 Object.defineProperty 的简单实现:

从0实现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 是 Vue 高效更新的关键。以下是虚拟 DOM 的简单实现和 Diff 算法:

从0实现vue

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

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

function patch(oldVnode, vnode) {
  if (!oldVnode) {
    // 初次渲染
    createElm(vnode);
  } else {
    // 更新
    const isRealElement = oldVnode.nodeType !== undefined;
    if (isRealElement) {
      // 挂载到真实 DOM
      const parent = oldVnode.parentNode;
      const refElm = oldVnode.nextSibling;
      parent.removeChild(oldVnode);
      createElm(vnode, parent, refElm);
    } else {
      // Diff 更新
      patchVnode(oldVnode, vnode);
    }
  }
  return vnode.elm;
}

function patchVnode(oldVnode, vnode) {
  // 简化版 Diff 逻辑
  if (oldVnode === vnode) return;
  const elm = (vnode.elm = oldVnode.elm);
  const oldCh = oldVnode.children;
  const ch = vnode.children;

  if (!vnode.text) {
    if (oldCh && ch) {
      updateChildren(elm, oldCh, ch);
    } else if (ch) {
      // 新增子节点
      addVnodes(elm, null, ch, 0, ch.length - 1);
    } else if (oldCh) {
      // 删除子节点
      removeVnodes(elm, oldCh, 0, oldCh.length - 1);
    }
  } else if (oldVnode.text !== vnode.text) {
    elm.textContent = vnode.text;
  }
}

模板编译

Vue 的模板编译将模板字符串转换为渲染函数。以下是简化的编译过程:

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 stack = [];
  let root, currentParent;
  parseHTML(template, {
    start(tag, attrs) {
      const element = { tag, attrs, children: [] };
      if (!root) root = element;
      if (currentParent) currentParent.children.push(element);
      stack.push(element);
      currentParent = element;
    },
    end() {
      stack.pop();
      currentParent = stack[stack.length - 1];
    },
    chars(text) {
      currentParent.children.push({ text });
    }
  });
  return root;
}

function generate(ast) {
  return `_c('${ast.tag}',${genData(ast.attrs)},${genChildren(ast.children)})`;
}

整合为 Mini-Vue

将以上模块整合为一个简单的 Vue 类:

class Vue {
  constructor(options) {
    this.$options = options;
    this._data = options.data;
    new Observer(this._data);
    this.$mount(options.el);
  }

  $mount(el) {
    const vm = this;
    const { render, template } = vm.$options;
    if (!render) {
      let template = vm.$options.template;
      if (!template && el) {
        template = document.querySelector(el).outerHTML;
      }
      vm.$options.render = compile(template);
    }
    new Watcher(vm, () => {
      const vnode = vm.$options.render.call(vm);
      patch(vm._vnode, vnode);
      vm._vnode = vnode;
    });
  }
}

class Watcher {
  constructor(vm, fn) {
    this.vm = vm;
    this.getter = fn;
    this.get();
  }

  get() {
    Dep.target = this;
    this.getter();
    Dep.target = null;
  }

  update() {
    this.get();
  }
}

使用示例

const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Mini-Vue!'
  },
  template: '<div>{{ message }}</div>'
});

以上代码实现了 Vue 的核心功能,包括数据响应式、虚拟 DOM 和模板编译。实际 Vue 的实现更加复杂,包含组件系统、指令、生命周期等更多功能。

标签: vue
分享给朋友:

相关文章

vue实现头像剪切

vue实现头像剪切

Vue 实现头像剪切的实现方法 使用 vue-cropperjs 库 vue-cropperjs 是一个基于 cropperjs 的 Vue 组件,专门用于图片裁剪。安装方式如下: npm inst…

vue如何实现注册

vue如何实现注册

实现用户注册功能 在Vue中实现注册功能通常需要结合前端表单和后端API交互。以下是完整的实现方案: 创建注册表单组件 注册表单需要包含用户名、邮箱、密码等基本字段,并进行表单验证: <te…

vue如何实现冒泡

vue如何实现冒泡

Vue 实现冒泡排序 在 Vue 中实现冒泡排序,可以通过数据绑定和响应式特性动态展示排序过程。以下是一个完整的实现示例,包含代码和详细说明。 数据准备 在 Vue 的 data 中定义一个数组作为…

vue怎么实现页面返回

vue怎么实现页面返回

Vue 实现页面返回的方法 在 Vue 中实现页面返回功能,可以通过以下几种方式完成,具体取决于项目使用的路由模式和技术栈。 使用 Vue Router 的编程式导航 通过 this.$route…

vue搜索过后实现分页

vue搜索过后实现分页

Vue 实现搜索后分页功能 数据绑定与搜索逻辑 在 Vue 组件中定义必要的数据属性: data() { return { searchQuery: '', currentPa…

vue实现压缩上传文件

vue实现压缩上传文件

压缩上传文件的实现方法 在Vue中实现文件压缩和上传功能,可以通过以下步骤完成。该方法结合了前端文件压缩库和HTTP请求,确保文件在上传前被有效压缩。 安装必要的依赖 需要使用compressorj…