news 2026/4/19 20:25:18

别再死记硬背了!用Vue和React的实战代码,5分钟搞懂MVC和MVVM到底差在哪

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再死记硬背了!用Vue和React的实战代码,5分钟搞懂MVC和MVVM到底差在哪

从计数器到待办清单:用Vue和React代码拆解MVC与MVVM的本质差异

每次面试被问到"MVC和MVVM有什么区别"时,你是不是也条件反射般背诵那些概念定义?作为经历过数十次技术面试的老前端,我深刻理解这种抽象概念仅靠文字描述有多难消化。今天我们就用最直观的方式——分别用MVC和MVVM思想实现两个经典案例(计数器&待办事项),在真实的代码对比中感受架构差异。

1. 先看本质:MVC与MVVM的DNA级区别

在开始写代码前,我们需要先建立最基础的认知框架。MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)都是为解决界面与数据分离而生的设计模式,但它们的协作方式有着根本性差异:

  • MVC的数据流是单向的:用户操作触发Controller,Controller修改Model后需要手动更新View
  • MVVM的数据流是双向的:ViewModel自动同步View和Model的状态变化,无需手动操作DOM

用个生活化的比喻:MVC就像传统邮件通信——你需要明确写好信件(数据)、装入信封(Controller处理)、投递到邮局(View更新);而MVVM更像是即时通讯软件,消息自动实时同步到对话双方。

2. 计数器案例:手动DOM操作 vs 自动数据绑定

2.1 原生JS实现MVC计数器

我们先看最经典的计数器实现。以下是完整的HTML结构:

<div id="mvc-counter"> <span id="count-display">0</span> <button id="increment-btn">+1</button> </div>

对应的JavaScript实现清晰地展示了MVC各层的职责:

// Model let counterModel = { value: 0, increment: function() { this.value += 1; return this.value; } }; // View function updateCounterView(value) { document.getElementById('count-display').textContent = value; } // Controller document.getElementById('increment-btn').addEventListener('click', () => { const newValue = counterModel.increment(); updateCounterView(newValue); // 必须手动更新视图 });

关键问题浮现了:每次数据变化后,我们必须显式调用updateCounterView()。在复杂应用中,这种手动同步会导致代码臃肿且难以维护。

2.2 Vue 3实现MVVM计数器

现在用Vue 3的Composition API实现相同功能:

<template> <div> <span>{{ count }}</span> <button @click="increment">+1</button> </div> </template> <script setup> import { ref } from 'vue'; const count = ref(0); function increment() { count.value++; // 自动触发视图更新 } </script>

注意到神奇之处了吗?我们没有操作任何DOMcount的变化会自动反映到界面上,这就是MVVM的核心优势——数据绑定。ViewModel(Vue实例)在背后建立了响应式系统,自动处理数据与视图的同步。

3. 待办事项:复杂场景下的架构差异放大

计数器可能太简单,我们升级到更典型的待办事项应用。比较两种实现方式,差异会更加明显。

3.1 MVC版待办事项的痛点

用纯JavaScript实现待办事项的MVC架构:

// Model const todoModel = { items: [], addItem: function(text) { this.items.push({ text, completed: false }); }, toggleItem: function(index) { this.items[index].completed = !this.items[index].completed; } }; // View function renderTodoList() { const listEl = document.getElementById('todo-list'); listEl.innerHTML = todoModel.items.map((item, index) => ` <li class="${item.completed ? 'completed' : ''}"> <input type="checkbox" ${item.completed ? 'checked' : ''} onchange="controller.toggleItem(${index})"> <span>${item.text}</span> </li> `).join(''); } // Controller const controller = { addItem: function() { const inputEl = document.getElementById('todo-input'); todoModel.addItem(inputEl.value); inputEl.value = ''; renderTodoList(); // 必须手动重绘整个列表 }, toggleItem: function(index) { todoModel.toggleItem(index); renderTodoList(); // 必须手动重绘整个列表 } };

每次数据变更都要重新渲染整个列表,这在性能和维护性上都是灾难。更糟的是,视图逻辑(HTML字符串拼接)与业务逻辑混杂在一起。

3.2 React Hooks实现的MVVM方案

用React with Hooks实现相同功能:

import { useState } from 'react'; function TodoApp() { const [items, setItems] = useState([]); const [inputValue, setInputValue] = useState(''); const addItem = () => { setItems([...items, { text: inputValue, completed: false }]); setInputValue(''); }; const toggleItem = index => { const newItems = [...items]; newItems[index].completed = !newItems[index].completed; setItems(newItems); }; return ( <div> <input value={inputValue} onChange={e => setInputValue(e.target.value)} /> <button onClick={addItem}>Add</button> <ul> {items.map((item, index) => ( <li key={index} className={item.completed ? 'completed' : ''}> <input type="checkbox" checked={item.completed} onChange={() => toggleItem(index)} /> <span>{item.text}</span> </li> ))} </ul> </div> ); }

React的MVVM实现展现了几个关键优势:

  1. 声明式渲染:UI自动响应状态变化,无需手动DOM操作
  2. 组件化:视图和逻辑保持内聚但解耦
  3. 高效更新:虚拟DOM机制确保只更新必要的部分

4. 如何根据场景选择架构模式

经过以上两个案例的对比,我们可以总结出一些实用的选择建议:

考量维度MVC更适合场景MVVM更适合场景
项目规模中小型项目中大型复杂项目
团队技能熟悉原生JS的团队熟悉现代框架的团队
交互复杂度简单交互复杂数据驱动的交互
性能要求需要精细控制DOM更新的场景需要快速开发迭代的场景
测试需求需要单独测试视图逻辑需要高覆盖率单元测试

实际项目中的混合使用:现代前端开发往往不是非此即彼的选择。比如在React中:

  • 全局状态管理(如Redux)采用类MVC模式
  • 组件内部使用MVVM模式
  • 路由配置可能是Mediator模式

这种架构的灵活性正是现代前端框架的强大之处。理解这些模式的本质差异,能帮助我们在不同场景下做出合理的技术决策。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 20:19:59

2025届毕业生推荐的六大降重复率助手横评

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 让AIGC生成内容的人造痕迹得以降低&#xff0c;其核心之处在于对机器输出的规律性特征予以削…

作者头像 李华
网站建设 2026/4/19 20:16:51

从零到精飞:APM多旋翼核心参数调校实战指南

1. APM飞控入门&#xff1a;从组装到基础参数设置 第一次接触APM飞控的新手常会被密密麻麻的参数表吓到。我刚开始调试植保无人机时&#xff0c;光是理解PID三个字母就花了整整一周。其实只要掌握核心逻辑&#xff0c;调参就像给汽车做四轮定位——有标准流程可循。 多旋翼飞控…

作者头像 李华
网站建设 2026/4/19 20:14:43

房产租赁管理|基于springboot + vue房产租赁管理系统(源码+数据库+文档)

房产租赁管理系统 目录 基于springboot vue房产租赁管理系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue房产租赁管理系统 一、前言 博主介绍&…

作者头像 李华
网站建设 2026/4/19 20:11:25

避开这些坑!STM32使用W25Q64时关于擦除、写入和SPI时序的实战经验

STM32与W25Q64实战指南&#xff1a;避开SPI闪存开发的五大深坑 在嵌入式系统开发中&#xff0c;外部闪存扩展是提升数据存储能力的常见方案。W25Q64作为一款8MB容量的SPI NOR Flash&#xff0c;因其性价比高、接口简单而广受欢迎。但许多开发者在实际项目中&#xff0c;往往会…

作者头像 李华
网站建设 2026/4/19 20:11:18

Qwen3-VL-8B-Instruct-GGUF性能实测:单卡24G流畅运行,推理速度超预期

Qwen3-VL-8B-Instruct-GGUF性能实测&#xff1a;单卡24G流畅运行&#xff0c;推理速度超预期 1. 颠覆认知的轻量级多模态模型 当我第一次看到Qwen3-VL-8B-Instruct-GGUF的规格参数时&#xff0c;说实话是持怀疑态度的。一个仅有8B参数的模型&#xff0c;号称能完成原本需要70…

作者头像 李华