当前位置:首页 > VUE

手动实现vue视图

2026-02-19 04:54:29VUE

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

Vue 的视图更新依赖于数据劫持和依赖收集,通过监听数据变化触发视图更新。以下是简化版实现的核心步骤:

数据劫持(响应式系统)

使用 Object.definePropertyProxy 拦截数据访问和修改:

function defineReactive(obj, key, val) {
  const dep = new Dep(); // 依赖收集器

  Object.defineProperty(obj, key, {
    get() {
      if (Dep.target) {
        dep.addSub(Dep.target); // 收集依赖
      }
      return val;
    },
    set(newVal) {
      if (newVal === val) return;
      val = 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;
  }
  update() {
    const value = this.get();
    if (value !== this.value) {
      this.cb.call(this.vm, value, this.value);
      this.value = value;
    }
  }
  get() {
    return this.vm._data[this.exp]; // 简化版直接访问数据
  }
}

模板编译

实现简单的模板解析和指令处理:

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

  function replace(frag) {
    Array.from(frag.childNodes).forEach(node => {
      if (node.nodeType === 3) { // 文本节点
        const text = node.textContent;
        const reg = /\{\{(.*?)\}\}/g;
        if (reg.test(text)) {
          const exp = RegExp.$1.trim();
          new Watcher(vm, exp, newVal => {
            node.textContent = text.replace(reg, newVal);
          });
          node.textContent = text.replace(reg, vm._data[exp]);
        }
      }
      if (node.nodeType === 1) { // 元素节点
        Array.from(node.attributes).forEach(attr => {
          if (attr.name.startsWith('v-')) {
            const exp = attr.value;
            new Watcher(vm, exp, newVal => {
              node.value = newVal; // 简化版仅处理v-model
            });
            node.addEventListener('input', e => {
              vm._data[exp] = e.target.value;
            });
            node.value = vm._data[exp];
          }
        });
      }
      if (node.childNodes && node.childNodes.length) {
        replace(node);
      }
    });
  }
  replace(fragment);
  el.appendChild(fragment);
}

整合实现

创建 Vue 类整合上述功能:

手动实现vue视图

class Vue {
  constructor(options) {
    this.$options = options;
    this._data = options.data;
    this.observe(this._data);
    compile(options.el, this);
  }
  observe(data) {
    Object.keys(data).forEach(key => {
      defineReactive(data, key, data[key]);
    });
  }
}

使用示例

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

<script>
  new Vue({
    el: '#app',
    data: {
      message: 'Hello Vue'
    }
  });
</script>

实现要点

  • 响应式系统通过数据劫持实现自动依赖收集
  • 每个数据属性对应一个 Dep 实例管理依赖
  • 每个模板绑定对应一个 Watcher 实例触发更新
  • 编译阶段解析模板并建立数据与视图的关联

以上实现省略了虚拟 DOM、组件系统等复杂功能,但展示了 Vue 响应式视图的核心原理。实际应用中还需考虑性能优化、生命周期管理等更多细节。

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

相关文章

vue实现冰墩墩

vue实现冰墩墩

使用 Vue 实现冰墩墩动画 通过 Vue 的动画特性和 SVG 技术,可以动态渲染冰墩墩的形象。以下是具体实现方法: 准备 SVG 素材 冰墩墩的形象通常由多个 SVG 路径组成,包括身体轮廓、面…

vue实现同步

vue实现同步

Vue 实现同步的方法 在 Vue 中实现同步操作通常涉及数据绑定、状态管理和异步操作的处理。以下是几种常见的方法: 使用计算属性(Computed Properties) 计算属性基于响应式依赖进…

vue实现rtc

vue实现rtc

Vue 实现 RTC 的步骤 安装依赖 在 Vue 项目中安装 WebRTC 相关依赖,如 simple-peer 或 peerjs,用于简化 WebRTC 的实现。 运行以下命令安装 simple-…

vue el 实现

vue el 实现

Vue 中使用 Element UI (el) 的实现方法 Element UI 是一个基于 Vue 的组件库,提供丰富的 UI 组件,常用于快速构建企业级中后台产品。以下介绍 Vue 项目中集成和使…

vue轮播实现

vue轮播实现

Vue 轮播实现方法 使用第三方库(推荐) 安装 swiper 或 vue-awesome-swiper 库,快速实现功能丰富的轮播效果。 以 vue-awesome-swiper 为例: npm…

vue实现listview

vue实现listview

Vue 实现 ListView 的方法 基础列表渲染 使用 v-for 指令可以轻松实现基础列表渲染。在 Vue 中,v-for 用于遍历数组或对象,生成动态列表。 <template>…