当前位置:首页 > JavaScript

js 实现mvvm

2026-02-02 09:17:15JavaScript

js 实现mvvm

MVVM 实现原理

MVVM(Model-View-ViewModel)是一种前端架构模式,核心在于数据绑定和视图与数据的自动同步。在 JavaScript 中实现 MVVM 通常需要以下几个关键部分:

  • 数据劫持/代理:通过 Object.definePropertyProxy 监听数据变化。
  • 依赖收集:在数据读取时收集依赖(如模板中的变量),数据变化时通知依赖更新。
  • 模板编译:解析模板中的指令(如 v-model{{}}),绑定数据与视图。

核心代码实现

数据劫持(基于 Proxy

class Observer {
  constructor(data) {
    return this.defineReactive(data);
  }

  defineReactive(data) {
    const dep = new Dep();
    return new Proxy(data, {
      get(target, key) {
        Dep.target && dep.addSub(Dep.target); // 收集依赖
        return target[key];
      },
      set(target, key, value) {
        target[key] = value;
        dep.notify(); // 触发更新
        return true;
      },
    });
  }
}

依赖管理

class Dep {
  constructor() {
    this.subs = [];
  }
  addSub(sub) {
    this.subs.push(sub);
  }
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}
Dep.target = null; // 全局唯一依赖标记

编译模板(简单示例)

class Compiler {
  constructor(el, vm) {
    this.el = document.querySelector(el);
    this.vm = vm;
    this.compile(this.el);
  }

  compile(node) {
    Array.from(node.childNodes).forEach(child => {
      if (child.nodeType === 3) { // 文本节点
        this.compileText(child);
      } else if (child.nodeType === 1) { // 元素节点
        this.compileElement(child);
      }
      if (child.childNodes.length) {
        this.compile(child);
      }
    });
  }

  compileText(node) {
    const text = node.textContent;
    const reg = /\{\{(.*?)\}\}/g;
    if (reg.test(text)) {
      const key = RegExp.$1.trim();
      new Watcher(this.vm, key, val => {
        node.textContent = text.replace(reg, val);
      });
    }
  }
}

观察者(Watcher)

class Watcher {
  constructor(vm, key, cb) {
    this.vm = vm;
    this.key = key;
    this.cb = cb;
    Dep.target = this;
    this.vm[this.key]; // 触发 getter,收集依赖
    Dep.target = null;
  }
  update() {
    this.cb(this.vm[this.key]);
  }
}

完整 MVVM 类

class MVVM {
  constructor(options) {
    this.$el = options.el;
    this.$data = options.data;
    new Observer(this.$data);
    new Compiler(this.$el, this);
    this.proxyData(this.$data);
  }

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

使用示例

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

<script>
  const vm = new MVVM({
    el: '#app',
    data: { message: 'Hello MVVM!' },
  });
</script>

关键点说明

  1. 数据劫持:通过 ProxyObject.defineProperty 监听数据变化。
  2. 依赖收集:在模板编译过程中,解析 {{}} 或指令时会创建 Watcher,触发数据的 getter 从而收集依赖。
  3. 更新触发:数据变化时通过 setter 通知 Dep,进而调用所有 Watcherupdate 方法更新视图。

此实现为简化版,实际框架(如 Vue)会处理更多边界条件和性能优化。

js 实现mvvm

标签: jsmvvm
分享给朋友:

相关文章

vue实现js休眠

vue实现js休眠

Vue 中实现 JavaScript 休眠 在 Vue 中实现 JavaScript 休眠通常需要使用异步方式,以避免阻塞主线程。以下是几种常见方法: 使用 setTimeout 和 Promis…

js实现跳转

js实现跳转

使用 window.location 跳转 通过修改 window.location.href 实现页面跳转,这是最常用的方法。 window.location.href = 'https://…

js实现图片上传

js实现图片上传

图片上传的基本实现 使用HTML的<input type="file">元素配合JavaScript的File API可以实现图片上传功能。HTML部分需要创建一个文件选择输入框和一个用于…

js实现全屏

js实现全屏

实现全屏的基本方法 使用JavaScript实现全屏功能主要依赖Element.requestFullscreen()方法。现代浏览器均支持此API,但不同浏览器可能需要添加前缀。 // 触发全屏…

js实现日历

js实现日历

实现日历的基本思路 使用JavaScript实现日历的核心是动态生成日期表格,并处理月份切换逻辑。需要计算当前月的天数、起始星期几,并动态渲染到页面上。 获取当前日期信息 通过Date对象获取当前年…

jquery.js

jquery.js

jQuery 是一个快速、简洁的 JavaScript 库,简化了 HTML 文档遍历、事件处理、动画设计和 Ajax 交互等操作。以下是关于 jQuery.js 的核心信息和使用方法: 获取 j…