【Vue】从 MVC 到 MVVM:前端架构演变与 Vue 的实践之路
个人博客:haichenyi.com。感谢关注
一. 目录
- 一–目录
- 二–架构模式的演变背景
- 三–MVC:经典的分层起点
- 四–MVP:面向接口的解耦尝试
- 五–MVVM:数据驱动的终极形态
- 六–Vue:MVVM 的现代化实践
二. 架构模式的演变背景
在软件开发中,架构模式是解决代码组织,职责分离和可维护行的核心方案。一个"好"的架构可以少很多不必要的麻烦。这个"好"就很关键,虽然架构模式经历了从MVC——>MVP——>MVVM的演变,但是,不一定后者比前者好。比方说:你一个小项目,MVC就够用了,非要去使用MVP,MVVM,就会多写很多无用代码。要结合多方面去考虑。软件开发的终极目标是高类聚,低耦合 。但是,还是需要结合实际项目去选择。18年MVVM刚兴起的时候,就写过一篇三者的区别的文章
MVC、MVP、MVVM比较。回顾了一下,感觉还是适用的。
三. MVC:经典的分层起点
- 核心思想
- Model:管理数据和业务逻辑
- View:呈现给用户看的界面
- Controller:接收用户输入,协调Model和View
- 典型流程
2.1 用户点击按钮触发点击事件,传递到Controller
2.2 Controller触发Model的事件去拿数据
2.2 Model数据更新之后,通知Controller更新view
//伪代码如下
let tvContent = document.getElementById("tv_content")
document.getElementById("btn").onclick = function () {axios.post().then(res=>{let data = res.datatvContent.textContent = data})
}
//当前页面获取view的某个组件的引用
//用户点击按钮,触发网络请求,拿到数据
//拿到数据之后,更新tvContent的内容
//当前页面就是Controller,网络请求包装的类就是Model,组件就是view
//Controller控制Model,model拿到数据之后控制view刷新界面
//代码少,逻辑简单,看不出来啥问题。挺好用的。但是,代码多,逻辑复杂呢?
//(前面就说了架构要根据实际项目情况来看)
- 局限性
- View和Model直接交互,耦合度高
- Controller臃肿:业务代码全都写在Controller中
四. MVP:面向接口的解耦尝试
- 核心改进
- Presenter(协调者):取代Controller,通过接口与view通信
- View被动化,只负责页面更新,逻辑由Presenter处理
- 典型流程
2.1 View接收用户操作,调用Presenter接口
2.2 Presenter操作Model处理数据
2.3 Model返回结果后,Presenter通过View接口更新页面
//伪代码如下,H5没有接口的概念,我都不知道怎么举例子
//这么理解,接口就是定义了一个一个的功能,需要有实现类去实现。
//还是上面的例子:用户点击按钮更新页面
interface IHome {update(content)
}class HomeImpl implements IHome {tvContent;constructor() {this.tvContent = document.getElementById("tv_content")}update(content: string) {this.tvContent.textContent = content}
}class HomePresenter {iHome: IHomeconstructor(iHome: IHome) {this.iHome = iHome}getData() {Axions.post().then(res=>{this.iHome.update(res.data)})}
}
let homePresenter = new HomePresenter(new HomeImpl())
document.getElementById("btn")?.onclick = function () {homePresenter.getData()
}
//上面的IHome接口,就是页面更新的定义,HomeImpl就是这个接口的实现
//如果,页面有很多种显示需要处理,就需要定义多个方法,需要多个实现,以便于后面P层调用
//HomePresenter就是P层,负责数据处理,和使用接口的引用更新页面
//按钮点击,触发P层逻辑。
//这只是最简单的写法,有很多优化点。Android里面用的比较多
- 优势与不足
- 优势:View和Model完全解耦
- 不足:需要手动维护大量的接口,代码冗余
五. MVVM:数据驱动的终极形态
- 核心思想
- ViewModel:作为view和model的桥梁,通过数据绑定实现自动同步
- 双向绑定:view的输入自动更新model,model数据变化自动刷新view
- 典型流程
2.1 view通过模板语法(如{{data}}),绑定到ViewModel
2.2 ViewModel监听到Model变化,并转换为View所需要的数据格式
2.3 用户操作触发ViewModel的方法,更新Model
//这么举例子呢,其实,万变不离其中,你不做的事情,都是框架帮你做的。
//比方说,Vue的响应式编程,你只用改变数据,页面自动更新。啥都不干,页面怎么可能知道数据遍了,从而自动更新呢?
//实际上就是发布订阅者模式触发更新,那么,是谁发布,谁订阅呢?放到后面第六部分讲
- 优势
- 开发高效:减少手动 DOM 操作,聚焦数据逻辑
- 动态更新:适合实时数据展示
- 缺点:学习成本高,上手慢。原理复杂,遇到问题,不容易定位
六. Vue:MVVM 的现代化实践
先说概念:Vue.js是mvvm模式集大成者,通过响应式系统和申明试模板,简化了数据绑定。并引入组件化解决复杂场景的问题。
6.1 Vue中MVVM的映射关系
| MVVM层 | Vue实现 |
|---|---|
| Model | data属性 |
| View | 模板(templtate)和样式(style) |
| ViewModel | Vue组件实例(暴露:data,computed,methods) |
6.2 双向绑定的原理:Vue 的响应式系统通过以下步骤实现:
- 数据劫持
- vue2是使用 Object.defineProperty 监听对象属性。
- vue3是使用Proxy代理对象,支持深层次监听
// Vue 2 数据劫持示例
function defineReactive(obj, key, val) {Object.defineProperty(obj, key, {get() {dep.depend(); // 收集依赖return val;},set(newVal) {val = newVal;dep.notify(); // 触发更新}});
}
//这里插一句题外话,这个响应式的设计模式,就是观察者模式
//数据本身就是被观察者,get方法里面收集依赖,就是收集观察者,set方法里面触发更新,就是通知观察者数据发生了变化
//vuex使用的是发布订阅者模式。
//下一篇文章。就讲讲这两种设计模式吧。
- 依赖收集
- 每个组件对应一个 Watcher,在渲染时访问数据属性,触发 getter 收集依赖。
- 分发更新
- 数据修改时触发 setter,通知所有关联的 Watcher 重新渲染(通过虚拟 DOM 对比更新真实 DOM,Diff算法)。
6.3 示例:数据变化驱动视图更新
<template><div><!-- 双向绑定:v-model 语法糖 --><input v-model="message" /><p>{{ reversedMessage }}</p></div>
</template><script>
export default {data() {return { message: "Hello Vue!" }; // Model},computed: {reversedMessage() { // ViewModel 逻辑return this.message.split('').reverse().join('');}}
}
</script>
Vue 的双向绑定,解析如下:
HTML 模板
<div id="app"><input v-model="message" /><p>{{ reversedMessage }}</p>
</div>
JavaScript 逻辑
// 模拟 Vue 实例
const data = { message: "Hello" };// 1. 数据劫持
defineReactive(data, "message", data.message);// 2. 计算属性(依赖 message)
const computed = {reversedMessage: () => data.message.split("").reverse().join("")
};// 3. 模板渲染 Watcher
new Watcher(() => {//归根结底,页面更新的方法,还是这个。我们前面说的mvc,mvp页面更新也是这个方法//所以,你以为它很神奇,其实,底层原理都是一样的。主要还是看每个人的思路。document.querySelector("p").textContent = computed.reversedMessage();
});// 4. 双向绑定(输入框 → 数据)
document.querySelector("input").addEventListener("input", (e) => {data.message = e.target.value; // 修改数据 → 触发 setter → 更新视图
});
效果:
- 输入框内容变化时,data.message 更新。
- reversedMessage 自动重新计算,p标签内容实时更新。
相关文章:
【Vue】从 MVC 到 MVVM:前端架构演变与 Vue 的实践之路
个人博客:haichenyi.com。感谢关注 一. 目录 一–目录二–架构模式的演变背景三–MVC:经典的分层起点四–MVP:面向接口的解耦尝试五–MVVM:数据驱动的终极形态六–Vue:MVVM 的现代化实践 二. 架构模…...
prototype`和`__proto__`有什么区别?如何手动修改一个对象的原型?
在 JavaScript 中,prototype 和 __proto__ 都与原型链相关,但它们的角色和用途有本质区别: 1. prototype 和 __proto__ 的区别 特性prototype__proto__归属对象仅函数对象拥有(如构造函数)所有对象默认拥有࿰…...
Flask+Influxdb+grafna构建电脑性能实时监控系统
Influx下载地址,这里下载了以下版本influxdb-1.8.5_windows_amd64.zip 运行前需要先启动Influx数据库: 管理员方式运行cmd->F:->cd F:\influxdb\influxdb-1.8.5-1->influxd -config influxdb.conf,以influxdb.conf配置文件启动数…...
关于链接库
在 C# 中,链接库主要分为两种类型:托管链接库和非托管链接库,以下为你详细介绍它们的特点和导入方式: 托管链接库 特点 托管链接库通常是用 .NET 兼容的语言(如 C#、VB.NET 等)编写的,运行在…...
若伊微服务版本教程(自参)
第一步 若伊官网下载源码 https://ruoyi.vip/ RuoYi-Cloud: 🎉 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统,同时提供了 Vue3 的版本 git clone 到 本地 目录如下: 第二部 参考官网 运行部署说明 环境部署…...
数据库性能优化(sql优化)_分布式优化思路01_yxy
数据库性能优化_分布式优化思路01 1 分布式数据库的独特挑战2 分布式新增操作符介绍2.1 数据交换操作符(ESEND/ERECV):2.2 数据迭代操作符GI:3 核心优化策略(一)_分区裁剪优化3.1 普通分区裁剪3.2 动态分区裁剪1 分布式数据库的独特挑战 在分布式数据库系统中,核心为数据被…...
ESP32与STM32哪种更适合初学者?
目录 1、ESP32:物联网时代的“网红” 2、STM32:工业界的“常青树” 3、到底谁更容易? 无论是刚入坑的小白,还是想扩展技术栈的老鸟,在选择主力 MCU 时,学习曲线绝对是重要的考量因素。ESP32 以其强大的 …...
秒杀秒抢系统开发:飞算 JavaAI 工具如何应对高并发难题?
秒杀、秒抢活动已成为电商促销与吸引流量的常用手段。然而,此类活动所带来的高并发访问,对系统性能构成了巨大挑战。如何确保系统在高并发场景下依然能够稳定、高效运行,成为开发者亟待解决的关键问题。飞算 JavaAI 工具作为一款功能强大的开…...
未启用CUDA支持的PyTorch环境** 中使用GPU加速解决方案
1. 错误原因分析 根本问题:当前安装的PyTorch是CPU版本,无法调用GPU硬件加速。当运行以下代码时会报错:model YOLO("yolov8n.pt").to("cuda") # 或 .cuda()2. 解决方案步骤 步骤1:验证CUDA可用性 在Pyth…...
C# 将Excel格式文件导入到界面中,用datagridview显示
界面按钮不做介绍。 主要代码: //用于获取从上一个页面传过来datagridview标题 public DataTable GetHeader { get; set; } private void UI_EXPINFO_Load(object sender, EventArgs e) { //页面加载显示listbox1中可…...
Spring Boot整合难点?AI一键生成全流程解决方案
在当今的软件开发领域,Spring Boot 凭借其简化开发流程、快速搭建项目的优势,成为了众多开发者的首选框架。然而,Spring Boot 的整合过程并非一帆风顺,常常会遇到各种难点。而飞算 JavaAI 的出现,为解决这些问题提供了…...
分享一下这几天在公司学到的东西
这几天我学到了很多东西 (1)我自己原来写项目,前后端联调用的都是postman,然后直接测试接口,然后连一下就完了。这几天我接触到了apifox的Mock这个东西!我知道了一个前端工程师进行前后端链条的时候&#…...
Java转Go日记(一):Slice解密
1.切片通过函数,传的是什么? package mainimport ("fmt""reflect""unsafe" )func main() {s : make([]int, 5, 10)PrintSliceStruct(&s)test(s) }func test(s []int) {PrintSliceStruct(&s) }func PrintSliceStr…...
MySQL 锁机制全景图:分类、粒度与示例一图掌握
✅ 一、按粒度分类(锁的范围大小) 1. 表级锁(Table Lock) 锁住整张表粒度大,开销小,并发性差常见于:MyISAM 引擎 📌 示例: LOCK TABLES user WRITE; -- 会锁住整个 u…...
STM32江科大----------PID算法
声明:本人跟随b站江科大学习,本文章是观看完视频后的一些个人总结和经验分享,也同时为了方便日后的复习,如果有错误请各位大佬指出,如果对你有帮助可以点个赞小小鼓励一下,本文章建议配合原视频使用❤️ 如…...
架构师面试(二十九):TCP Socket 编程
问题 今天考察网络编程的基础知识。 在基于 TCP 协议的网络 【socket 编程】中可能会遇到很多异常,在下面的相关描述中说法正确的有哪几项呢? A. 在建立连接被拒绝时,有可能是因为网络不通或地址错误或 server 端对应端口未被监听&#x…...
基础学习(4): Batch Norm / Layer Norm / Instance Norm / Group Norm
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言1 batch normalization(BN)2 Layer normalization (LN)3 instance normalization (IN)4 group normalization (GN)总结 前言 对 norm/batch/instance/group 这…...
局域网内Docker镜像共享方法
在局域网内将Docker镜像构建并传输到另一台电脑,可以通过以下几种方法实现。以下是具体步骤及注意事项,结合不同场景的适用方案: 方法一:使用 docker save 和 docker load 传输镜像文件 步骤说明 在构建机上保存镜像 通过 docker…...
Idea集成AI:CodeGeeX开发
当入职新公司,或者调到新项目组进行开发时,需要快速熟悉项目代码 而新的项目代码,可能有很多模块,很多的接口,很复杂的业务逻辑,更加有与之前自己的代码风格不一致的现有复杂代码 更别提很多人写代码不喜…...
HTTP HTTPS RSA
推荐阅读 小林coding HTTP篇 文章目录 HTTP 80HTTP 响应码1xx:信息性状态码(Informational)2xx:成功状态码(Success)3xx:重定向状态码(Redirection)4xx:客户端…...
【深度学习与大模型基础】第10章-期望、方差和协方差
一、期望 ——————————————————————————————————————————— 1. 期望是什么? 期望(Expectation)可以理解为“长期的平均值”。比如: 掷骰子:一个6面骰子的点数是1~6&#x…...
Elasticvue-轻量级Elasticsearch可视化管理工具
Elasticvue一个免费且开源的 Elasticsearch 在线可视化客户端,用于管理 Elasticsearch 集群中的数据,完全支持 Elasticsearch 版本 8.x 和 7.x. 功能特色: 集群概览索引和别名管理分片管理搜索和编辑文档REST 查询快照和存储库管理支持国际…...
危化品经营单位安全生产管理人员备考要点
危化品经营单位安全生产管理人员备考要点 📌 考试核心内容 ✅ 必考法规: 《危险化学品安全管理条例》重点条款(如经营许可条件) GB 18218-2018《重大危险源辨识》新标准 安全生产法律责任(罚款金额/刑事责任&…...
【python】OpenCV—Tracking(10.6)—People Counting
文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、涉及到的库函数6、参考来自 更多有趣的代码示例,可参考【Programming】 1、功能描述 借助 opencv-python,用 SSD 人形检测模型和质心跟踪方法实现对人群的计数 基于质心的跟踪可以参考 【pyt…...
使用KeilAssistant代替keil的UI界面
目录 一、keil Assistant的优势和缺点 二、使用方法 (1)配置keil的路径 (2)导入并使用工程 (3)默认使用keil自带的ARM编译器而非GUN工具链 一、keil Assistant的优势和缺点 在日常学…...
FreeRTOS菜鸟入门(五)·空闲任务与阻塞延时的实现
目录 1. 实现空闲任务 1.1 定义空闲任务的栈 1.2 定义空闲任务的任务控制块 1.3 创建空闲任务 2. 实现阻塞延时 2.1 vTaskDelay()函数 2.2 修改 vTaskSwitchContext()函数 3. SysTick 中断服务函数 4. SysTick 初始化函数 通过之前我们了解知道,任…...
Doris部署生产集群最低要求的部署方案
Doris生产集群最低部署方案(2025年4月版) 一、节点规划与数量 1. FE节点(Frontend) 数量:至少 3个节点(1个Follower 2个 Observer),确保高可用(HA)。角色分…...
JBOSS反序列化漏洞解析与防范策略CVE-2017-12149
JBOSS反序列化漏洞解析与防范策略 引言 JBOSS是一个流行的开源应用服务器,广泛应用于企业级应用程序的开发和部署。然而,由于其广泛的使用和复杂的架构,JBOSS也成为了黑客攻击的常见目标。近年来,多个JBOSS漏洞被曝光࿰…...
MySQL MVCC工作流程详解
MySQL MVCC工作流程详解 1. 基础概念 MVCC(多版本并发控制)是通过在每行记录后面保存多个版本来实现并发控制的技术,主要用于提供并发事务访问数据库时的读一致性。 2. 核心要素 2.1 事务ID(DB_TRX_ID) 每个事务都…...
Web3技术下数字资产数据保护的实践探索
在这个信息爆炸的时代,数字资产已经成为我们生活中不可或缺的一部分。随着Web3技术的兴起,它以其去中心化、透明性和安全性的特点,为数字资产的管理和保护提供了新的解决方案。本文将探讨Web3技术在数字资产数据保护方面的实践探索࿰…...
