写好代码之MVVC架构模式

MVC

  • 视图 (View):用户界面
  • 控制器 (Controller):业务逻辑
  • 模型 (Model):数据保存,渲染数据源

例如:

  1. view 收到dom点击指令到 Controller;
  2. Controller 完成业务逻辑后,要求Modal改变数据状态;
  3. Modal将新数据发送到View,用户得到反馈;

代码实现以Backbone.js 计数器示例:

html 复制代码
    <!DOCTYPE html>
<html>
<head>
  <title>Backbone MVC Counter</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.1/underscore-min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.0/backbone-min.js"></script>
</head>
<body>
  <div id="app">
    <div>count: <span id="count-display">0</span></div>
    <button id="increment-btn">加+1</button>
  </div>

  <script>
    // 1. Model (数据 + 逻辑)
    const CounterModel = Backbone.Model.extend({
      defaults: {
        count: 0
      },
      increment: function() {
        this.set({ count: this.get("count") + 1 }); // 更新数据
      }
    });

    // 2. View (UI + 事件监听)
    const CounterView = Backbone.View.extend({
      el: "#app", // 挂载点
      events: {
        "click #increment-btn": "handleIncrement" // 监听按钮点击
      },
      initialize: function() {
        this.model = new CounterModel(); // 初始化 Model
        this.listenTo(this.model, "change", this.render); // 监听 Model 变化
        this.render(); // 初始渲染
      },
      handleIncrement: function() {
        this.model.increment(); // 调用 Model 方法修改数据
      },
      render: function() {
        // 手动更新 DOM
        this.$("#count-display").text(this.model.get("count"));
        return this;
      }
    });

    // 启动应用
    new CounterView();
  </script>
</body>
</html>

MVC 数据流(Backbone.js)

  1. 用户点击按钮View 捕获事件,调用 handleIncrement
  2. View 调用 Model 方法increment() 修改数据。
  3. Model 触发 change 事件View 监听到变化,手动更新 DOM(render())。

特点

  • 手动 DOM 更新render() 方法)。
  • Model 和 View 解耦,但需要显式监听数据变化。
  • Controller 逻辑分散在 View 中(Backbone 没有严格独立的 Controller)。

MVVM

MVVM出现原因解决:

分离关注点,分离视图与业务逻辑

  • MVC中需要手动控制View和Model之间的双向数据绑定的繁琐逻辑,如上Backbone.js的示例,Controller分散在View中代码耦合度高,维护困难,测试困难;

  • MVVM引入视图模型(ViewModel)自动双向数据绑定,即修改定义的响应数据(vue:refreact:state),自动反应到数据在视图上的变化;让开发者只需要关注业务逻辑,不需要关心view和Model的绑定关系,由于ViewModel(业务处理数据逻辑)与View分离,可能独立于视图测试,提高测试效率。

Vue (MVVM 模式)

在 MVVM 中:

  • Modelref/reactive 数据。
  • View :模板(<template>)。
  • ViewModel<script setup> 中的逻辑(处理数据绑定和事件)。
代码实现
javascript 复制代码
<script setup>
import { ref } from 'vue'

// Model (数据)
const count = ref(0)

// ViewModel (逻辑)
const handleIncrement = () => {
  count.value += 1 // 修改数据,Vue 自动更新视图
}
</script>

<!-- View (模板) -->
<template>
  <div>count: {{ count }}</div>
  <button @click="handleIncrement">加+1</button>
</template>
MVVM 数据流(Vue)
  1. 用户点击按钮View 触发 @click 事件。
  2. ViewModel 执行 handleIncrement → 修改 count
  3. Vue 自动检测数据变化 → 更新 DOM(无需手动操作)。

特点

  • 自动 DOM 更新(响应式系统)。
  • 双向绑定 (表单输入可用 v-model)。
  • ViewModel 作为中间层,解耦 Model 和 View。

MVC vs. MVVM 对比

特性 Backbone.js (MVC) Vue (MVVM)
数据绑定 手动更新 DOM (render()) 自动(响应式系统)
代码量 较多(需手动监听和渲染) 较少(声明式模板)
职责分离 Model + View(Controller 混合在 View) Model + View + ViewModel(清晰分层)
适用场景 需要精细控制 DOM 的场景 快速开发数据驱动型应用

总结

通过MVC与MVVM比较,介绍了为什么MVC后会出现MVVM架构模式,主要是考虑开发效率,代码可维护和测试性考虑;分离关注点利用VM(视图模型),数据驱动视图,无需手动关注数据与视图双向绑定,日常编写Vue和React代码时,需要有意识的将VM(事件回调处理和数据请求等处理)与View(渲染内容)做隔离解耦,如下面:

javascript 复制代码
  const App = ()=>{
       const [count,setCount] = useState(0)   
       
       /*VM*/
       const handleClick = ()=>{
           setCount(preCount=> preCount+=1)
       }
       
       /*View*/
       return <div >
         {{count}}
          /* 不推荐,没有让VM 与 View 分离 */
           <button onClick={()=>{
             setCount(preCount=> preCount+=1) ❌
           }}>点击</button>
           
           <button onClick={handleClick}>点击</button> ✅
      </div>
  }
 

希望对你有帮助!如果有进一步问题,欢迎讨论 😊

相关推荐
年老体衰按不动键盘3 分钟前
快速部署和启动Vue3项目
java·javascript·vue
小小小小宇3 分钟前
一个小小的柯里化函数
前端
灵感__idea7 分钟前
JavaScript高级程序设计(第5版):无处不在的集合
前端·javascript·程序员
小小小小宇11 分钟前
前端双Token机制无感刷新
前端
小小小小宇13 分钟前
重提React闭包陷阱
前端
小小小小宇29 分钟前
前端XSS和CSRF以及CSP
前端
UFIT32 分钟前
NoSQL之redis哨兵
java·前端·算法
超级土豆粉39 分钟前
CSS3 的特性
前端·css·css3
星辰引路-Lefan40 分钟前
深入理解React Hooks的原理与实践
前端·javascript·react.js
wyn200011281 小时前
JavaWeb的一些基础技术
前端