当前位置:首页 > VUE

手动实现vue视图

2026-01-18 12:27:38VUE

手动实现 Vue 视图的核心逻辑

Vue 的核心是数据驱动的视图渲染,通过响应式系统和虚拟 DOM 实现高效更新。以下是手动实现简化版 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); // 收集当前 Watcher
        return value;
      },
      set(newVal) {
        if (newVal === value) return;
        value = newVal;
        observe(newVal); // 新值为对象时继续劫持
        dep.notify(); // 触发更新
      }
    });
  });
}

依赖收集与发布订阅

实现 Dep(依赖收集器)和 Watcher(观察者):

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

class Watcher {
  constructor(vm, exp, cb) {
    this.vm = vm;
    this.exp = exp;
    this.cb = cb;
    Dep.target = this;
    this.value = this.get(); // 触发 getter 收集依赖
    Dep.target = null;
  }
  get() {
    return this.exp.split('.').reduce((obj, key) => obj[key], this.vm);
  }
  update() {
    const newValue = this.get();
    if (newValue !== this.value) {
      this.cb(newValue);
      this.value = newValue;
    }
  }
}

模板编译

将模板转换为渲染函数,解析指令和插值表达式:

手动实现vue视图

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

  function replace(node) {
    const reg = /\{\{(.*?)\}\}/g;
    if (node.nodeType === 3) {
      const text = node.textContent;
      if (reg.test(text)) {
        const exp = RegExp.$1.trim();
        new Watcher(vm, exp, value => {
          node.textContent = text.replace(reg, value);
        });
        node.textContent = text.replace(reg, vm[exp]);
      }
      return;
    }
    if (node.nodeType === 1) {
      Array.from(node.attributes).forEach(attr => {
        if (attr.name.startsWith('v-')) {
          const exp = attr.value;
          if (attr.name === 'v-model') {
            node.value = vm[exp];
            new Watcher(vm, exp, value => {
              node.value = value;
            });
            node.addEventListener('input', e => {
              vm[exp] = e.target.value;
            });
          }
        }
      });
    }
    Array.from(node.childNodes).forEach(replace);
  }

  replace(fragment);
  el.appendChild(fragment);
}

虚拟 DOM 与 Diff 算法

实现简化版虚拟 DOM 和差异比对:

function createElement(tag, props, children) {
  return { tag, props, children };
}

function diff(oldNode, newNode) {
  if (oldNode.tag !== newNode.tag) {
    return node => {
      const newEl = document.createElement(newNode.tag);
      oldNode.el.parentNode.replaceChild(newEl, oldNode.el);
      return newEl;
    };
  }
  const patches = [];
  const propsPatches = diffProps(oldNode.props, newNode.props);
  if (propsPatches) {
    patches.push(node => {
      Object.entries(propsPatches).forEach(([k, v]) => {
        node.setAttribute(k, v);
      });
    });
  }
  const childrenPatches = diffChildren(oldNode.children, newNode.children);
  if (childrenPatches.length) {
    patches.push(node => {
      childrenPatches.forEach((patch, i) => {
        patch(node.childNodes[i]);
      });
    });
  }
  return node => patches.forEach(patch => patch(node));
}

初始化入口

整合以上模块实现迷你 Vue 类:

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

使用示例

<div id="app">
  <input v-model="message">
  <p>{{ message }}</p>
</div>

<script>
  new MiniVue({
    el: document.getElementById('app'),
    data() {
      return { message: 'Hello Vue' };
    }
  });
</script>

关键优化方向

  1. 批量异步更新:通过 nextTick 实现更新队列
  2. 组件系统:支持嵌套组件和生命周期
  3. 指令扩展:实现 v-forv-if 等复杂指令
  4. 性能监控:添加渲染耗时统计

以上实现展示了 Vue 的核心原理,实际工程中还需处理边缘情况和性能优化。

标签: 视图vue
分享给朋友:

相关文章

vue实现cs

vue实现cs

Vue 实现 CS(Client-Side)渲染的常见方法 Vue.js 是一个用于构建用户界面的渐进式框架,默认采用客户端渲染(CSR)。以下是几种常见的实现方式: 使用 Vue CLI 创建项目…

vue 实现跳转

vue 实现跳转

Vue 实现页面跳转的方法 在 Vue 中实现页面跳转通常可以通过以下几种方式实现,具体选择取决于项目需求和技术栈(如是否使用 Vue Router)。 使用 Vue Router 进行编程式导航…

vue下载实现

vue下载实现

Vue 下载实现方法 在 Vue 项目中实现文件下载功能可以通过多种方式完成,以下是几种常见的方法: 使用 <a> 标签实现下载 通过动态创建 <a> 标签并设置 href…

前端vue实现概率

前端vue实现概率

Vue实现概率功能的方法 在Vue中实现概率功能通常涉及随机数生成和概率计算。以下是几种常见实现方式: 基础概率实现 使用Math.random()生成0到1之间的随机数,与设定概率比较:…

vue  实现关联属性

vue 实现关联属性

Vue 实现关联属性 在 Vue 中实现关联属性通常涉及计算属性(computed properties)或侦听器(watchers),用于根据其他属性的变化动态更新目标属性。 使用计算属性 计算属…

vue实现登录认证

vue实现登录认证

Vue 登录认证实现方法 使用 Vue Router 和 Vuex 管理登录状态 在 Vue 项目中,通常使用 Vue Router 进行路由管理,Vuex 进行状态管理。登录认证的核心是验证用户身份…