MVC:

 介绍:

        MVC 模型即 Model View Controller(模型 视图 控制器)

        Model(模型):存储业务数据、验证、业务逻辑(不包含回调函数),

        View(视图):数据展示层,负责数据展示与交互,不能直接操作数据。

        Controller(控制器):负责接收 View 用户的操作,然后更改数据,同时更改 Model 层数据,是 M 和 V 的中间层。

 工作流程:

​

View <—> Controller <—> Model,单向通信为主,Controller是核心调度者。

 优缺点:

        优点:使用好时耦合性较低,部署快,可维护性高。

        缺点:使用不规范时耦合性极高,特别是 view 层和 Controller 层,其次是 View 层和 Model 层。

下面一个原生 js/HTML 实现 MVC 示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>高耦合 MVC(经典版)</title>
</head>
<body>
  <input type="text" id="input">
  <button id="addBtn">添加</button>
  <div id="list"></div>

  <script>
    // ======================
    // 1. Model(数据层)
    // ======================
    const Model = {
      items: [],
      addItem(text) {
        this.items.push(text);
      }
    };

    // ======================
    // 2. View(直接依赖 Model!!!耦合)
    // ======================
    const View = {
      render() {
        // View 直接读取 Model 数据!!!
        // View ←→ Model 直接耦合!
        document.getElementById('list').innerHTML 
          = Model.items.map(i => `<div>${i}</div>`).join('');
      }
    };

    // ======================
    // 3. Controller
    // ======================
    const Controller = {
      init() {
        // 直接操作 DOM 元素!View 和 Controller 耦合!
        document.getElementById('addBtn').onclick = () => {
          const text = document.getElementById('input').value.trim();
          if (text) {
            Model.addItem(text);
            View.render(); // 调用View
          }
        };
      }
    };

    Controller.init();
  </script>
</body>
</html>

可以很明显的看到缺点: Controller 直接操作 View 的内部元素 / 方法 ,即 controller 完全知道 view 里面有什么,要什么,这使得一个 view 的 controller 在其它 view 里面基本无法使用,view 和 controller 联系过于紧密,同时view 层对 model 层的访问效率极低。

View 层和 Model 层直接通信——如上图,View 初始渲染时直接使用在 Model 层查询状态,Model 数据更新后直接

MVP:

 介绍:

        MVP 模型即 Model View Presenter(模型 视图 主持人)。

        Model(模型):同 MVC 一样,都是数据存放地,但不和 View 直接耦合,下面会讲。

        View(视图):同 MVC 一样,都是数据展示地,也不和 Model 直接耦合。

        Presenter(主持人):是 MVP 的核心,负责连接 View 和 Model,直接解决 View 和 Model 耦合性问题,它接收 View 的用户操作,调用 Model 的方法处理数据,然后将处理好的数据推给 View,使视图更新。

 工作流程:

​

​

        这里就可以看到,Presenter 相较于 Controller 对于 View 和 Model 的约束作用更大,解决 MVC 的第二个耦合问题。

 优缺点:

        优点:降低了程序的耦合性,提高灵活性,即 视图与住处人 视图与模型 的耦合度降低了

        缺点:View 和 Presenter 的耦合性虽然低了,但写起来并不简单,需要 Presenter 把 view 中的所有方法都写下来,同时 view 也要暴漏所有的方法,更难受的是当数据变了要手动通知视图,视图变了要手动更改数据,写起来很繁琐。

    如下面代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>真正的 MVP(低耦合)</title>
</head>
<body>
  <input type="text" id="input">
  <button id="addBtn">添加</button>
  <div id="list"></div>

  <script>
    // ======================
    // 1. Model:完全独立
    // ======================
    const Model = {
      items: [],
      addItem(text) {
        this.items.push(text);
        return this.items;
      }
    };

    // ======================
    // 2. View:只暴露接口,不暴露内部元素
    // ======================
    const View = {
      // 内部元素全部私有化!
      $input: document.getElementById('input'),
      $list: document.getElementById('list'),
      $btn: document.getElementById('addBtn'),

      // 暴露给 Presenter 的【接口】
      getValue() {
        return this.$input.value.trim();
      },
      renderList(items) {
        this.$list.innerHTML = items.map(i => `<div>${i}</div>`).join('');
      },
      clearInput() {
        this.$input.value = '';
      },
      // 事件绑定由 View 自己做!只抛回调!
      bindAddClick(callback) {
        this.$btn.onclick = callback;
      }
    };

    // ======================
    // 3. Presenter:完全不碰 View 内部!只调接口
    // ======================
    const Presenter = {
      init() {
        // View 只给回调,Presenter 不知道按钮是什么
        View.bindAddClick(() => this.handleAdd());
      },

      handleAdd() {
        const text = View.getValue(); // 只调用接口,注意基本上所有view暴露的方法都要调用
        if (!text) return;

        const newList = Model.addItem(text);
        View.renderList(newList);
        View.clearInput();
      }
    };

    // 启动
    Presenter.init();
  </script>
</body>
</html>

MVVM:

 介绍:

        MVVM 模型即 Model View ViewModel (模型 视图 视图模型)

        Model(模型):数据存放地,同上

        View(视图):数据展示地,同上,可以通过指令(如 vue 中的v-model、v-bind)直接绑定ViewModel的数据,无需手动接收数据更新。

        ViewModel(视图模型):它负责将Model的数据转换为View可展示的格式(数据格式化),同时监听View的用户操作,反向修改Model的数据(双向绑定)。ViewModel通过「数据双向绑定」让View和Model自动同步,无需手动调度——当Model的数据变化时,View会自动更新;当用户操作View时,Model的数据也会自动修改。

 工作流程:

​

view 和 model 需要做的事情变化不大,但 viewmodel 相较于 presenter 变化确实极大

如下:

    • 持有 Model(数据来源)
    • 提供视图可绑定的数据
    • 监听 Model 变化 → 自动更新 View
    • 接收 View 操作 → 自动更新 Model

即它不再主动调用 view 暴露的方法了,而是通过数据双向绑定的方法来实现数据分配于更改,像 vue 里面通过 Object.defineProperty 方法实现数据劫持,vue3 里面使用 Proxy,都是 ViewModel 的表现形式。

优缺点:

        优点:解决了 MVC 和 MVP 都没有解决或完全解决的 Model 层和中间调节层(Controller/Presenter)的高度耦合性。提高了代码的重用性,写起来方便。

        缺点:类会增多,ViewModel会越加庞大,调用的复杂度增加。(但问题不大,相较于前两个算很好了,推荐推荐推荐)

代码示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>原生 JS 实现 MVVM(双向绑定)</title>
</head>
<body>
  <h3>MVVM 示例</h3>
  <input type="text" id="input">
  <div id="list"></div>

  <script>
    // ======================
    // 1. Model(数据层)
    // ======================
    const Model = {
      items: [],
      inputValue: ""
    };

    // ======================
    // 2. ViewModel(VM 核心:双向绑定)
    // ======================
    const ViewModel = {
      model: Model,
      viewInput: document.getElementById("input"),
      viewList: document.getElementById("list"),

      // 初始化:监听视图 + 监听数据
      init() {
        // 视图 → 数据
        this.viewInput.oninput = (e) => {
          this.model.inputValue = e.target.value;
        };

        // 数据 → 视图(自动渲染)
        this.observe(this.model, "inputValue", () => {
          this.viewInput.value = this.model.inputValue;
        });

        // 列表自动渲染
        this.observe(this.model, "items", () => {
          this.renderList();
        });
      },

      // 添加数据
      addItem() {
        if (this.model.inputValue) {
          this.model.items.push(this.model.inputValue);
          this.model.inputValue = "";
        }
      },

      // 渲染列表
      renderList() {
        this.viewList.innerHTML = this.model.items
          .map(i => `<div>${i}</div>`)
          .join("");
      },

      // 数据监听:数据变 → 视图自动变(MVVM 核心)
      observe(obj, key, callback) {
        let value = obj[key];
        Object.defineProperty(obj, key, {
          set(newVal) {
            value = newVal;
            callback(); // 自动更新视图
          },
          get() {
            return value;
          }
        });
      }
    };

    // ======================
    // 3. View(视图层:无逻辑!)
    // ======================
    // View 只做展示,不处理逻辑,不调用 VM
    document.getElementById("input").onkeydown = (e) => {
      if (e.key === "Enter") ViewModel.addItem();
    };

    // 启动
    ViewModel.init();
  </script>
</body>
</html>

上面的示例都是使用原生 js/HTML 进行的简单实现,可能有误,理解即可。

参考博客如下:

参考1

参考2

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐