当前位置:首页 > JavaScript

js 实现mvvm

2026-02-02 09:17:15JavaScript

MVVM 实现原理

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

js 实现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)会处理更多边界条件和性能优化。

标签: jsmvvm
分享给朋友:

相关文章

js实现跳转

js实现跳转

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

js实现论坛

js实现论坛

实现论坛的基本功能 使用JavaScript实现一个论坛需要结合前端和后端技术。前端可以使用React、Vue或Angular等框架,后端可以选择Node.js配合Express或Koa框架。数据库可…

js实现tab选项卡切换

js实现tab选项卡切换

实现Tab选项卡切换的JavaScript方法 使用纯JavaScript实现Tab切换功能,可以通过监听点击事件动态切换内容显示状态。以下是两种常见实现方式: 基础DOM操作实现 // 获取所有…

js jquery

js jquery

jQuery 简介 jQuery 是一个快速、简洁的 JavaScript 库,简化了 HTML 文档遍历、事件处理、动画设计和 Ajax 交互。它兼容多种浏览器,提供易于使用的 API,使开发者能够…

js实现目录

js实现目录

实现目录的基本思路 在JavaScript中实现目录功能通常涉及以下几个核心步骤:解析文档中的标题元素(如h1-h6),动态生成目录结构,并添加交互逻辑(如点击跳转)。以下是具体实现方法: 解析标题…

js节流实现

js节流实现

节流的概念 节流(Throttle)是一种限制函数执行频率的技术,确保函数在一定时间间隔内只执行一次。常用于滚动事件、窗口调整等高频触发的场景。 基础实现方法 使用时间戳判断是否执行函数: fun…