学前端框架之前,你需要先理解 MVC
MVC 软件架构设计模式鼎鼎大名,相信你已经听说过了,但你确定自己已经完全理解到 MVC 的精髓了吗?
如果你是新同学,没听过 MVC,那可以到网上搜一些文章来看看,不过你要有心理准备,那些文章大多都是偏后端的文章,而且大多都是概念性的,看完估计还是会一头雾水。
最终的结果就是,你可能会认为 MVC 模式是属于后端领域的,前端可能更应该去看 MVVM。
MVC 模式有一些变体,比如 MVVM、MVP 等等,但不管怎么变化,核心还是不变的,因此我们不需要管那么多概念上的弯弯绕绕,学习 MVC 的核心才是最主要的。
另外,MVC 是软件设计模式,设计模式是不区分语言的,所以也不是后端领域独有的。
实际上,我们前端开发的代码设计模式基本就是 MVC,这点后面我会说到。
因此,理解 MVC 对你来说至关重要,是最重要的基础之一,你对 MVC 的理解会影响到以后你的代码设计质量。
另外,前端框架有非常多,理解 MVC,能够帮助你更好地分类并理解这些前端框架。
因此,在学前端框架之前,你需要先理解 MVC。
什么是 MVC
MVC 全称是 Model-View-Controller,顾名思义,它是由以下 3 部分组成:
- Model:模型,你可以理解它是我们代码中的逻辑数据实体。
- View:视图,你可以理解它是用户看到的 UI 界面。
- Controller:控制器,你可以理解它是用来协调(解耦)Model 和 View 的。
MVC 的核心思想就是解耦 Model 和 View。
好了,MVC 的概念讲完了,就是这么简单,但有效。
MVC 的好处
听完概念,你可能会问,解耦 Model 和 View 有什么用呢?
我举一个栗子说明一下这里的好处。
假设我们维护一个电商平台,我们的商品卡片需要展示商品价格,类似下图:

商品卡片左下角的价格数据是从我们的接口返回的。
如果只有 MV 没有 C
我们先来看,如果只有 Model 和 View,没有 Controller 来进行解耦的话,会是这样:

在拿到接口数据之后,就把接口的数据直接传入给 UI 组件,UI 组件把这个价格原样展示出来。
可以看到,现在 price 字段返回的是浮点数,我们都知道,浮点数的计算非常麻烦,会有精度的问题。一般我们要处理浮点数运算,其中一个办法就是先把浮点数转成整数,运算之后,再把整数转回浮点数。
现在,后端同学因为浮点数计算的问题,对后端逻辑进行了整数化改造优化,接口返回的数据发生了变更,变成了这样:

price 字段返回了整数,同时也返回了放大倍数 base 字段,这样,当我们需要展示真实的价格时,用放大倍数字段处理一下就可以了。
然后业务又来了一个新的需求,就是这个店铺上线了分期付款功能,用户可以支付较小的一笔钱就能先拿到商品的使用权,后面再每个月支付剩余的钱,直到全部钱都付完为止。为了吸引用户,价格当然是显示地越少越好啦,因此产品希望我们给这个商品的价格显示每期支付的价格,比如下图这样:

接口又新增了一个 tenor 参数,代表这个商品可使用的分期数,这样做一定的计算之后,就能得到商品的每一期需要支付的价格,然后显示在商品卡片上。
上面这个例子是个极其简单的例子,但却是我们真实工作当中最经常碰到的事情 —— 迭代和变更。上面描述了 2 个功能迭代,可以看到,每次新功能迭代,我们的接口数据 (Model) 和 UI 组件 (View) 都要发生变更,在图中我用红色标记出来了。
可以看到,只要 Model 发生变更,我们的 View 就要跟着一起变更,在我们的例子中,就是全部模块都要变更,这是一件令人烦恼的事情。在真实项目中,当你接到一个需求,发现要在所有模块都修改代码的时候,是非常容易崩溃的。而且,这样的变更,非常容易出问题,然后带来一系列糟糕的影响,比如低绩效,被刀等等。
如果是 MVC 会怎么样
如果我们添加一个 Controller,会变成这样:

商品价格就是纯透传,没干什么事情。然后我们来看看放大倍数迭代:

我们在 Controller 处理好价格的转换逻辑,然后再传给商品卡片组件,组件还是跟之前一样,传入什么价格,直接显示就好了。
然后再看看分期迭代:

同样的,我们在 Controller 处理好分期价格的处理逻辑,然后把处理之后的价格信息传给商品卡片组件就行了。
从上图可以直观地看到,我们在 Model 和 View 之间添加了 Controller,这样就解耦了 Model 和 View。当 Model 发生变更的时候,所有的变更处理都收拢在 Controller,而不需要变更 View。
可能刚入门的同学会问,如果统计图中红色色块的数量,那不是一样的吗?这里只是把过去在 View 中的代码抽到 Controller 这里而已,当 Model 发生变更的时候,Controller 也是一样要跟着变更的,代码量也没变呀。
单看这个简单例子的表现是这样的,好像并没有很神奇的优化效果。但你要记住的是:UI 组件的维护成本 >> 纯逻辑的维护成本。
由于篇幅问题,这里就不太好展开来讲了,如果你是新同学,没有比较多的项目维护经验的话,那只需要记住这句话,还有下面这些优势项就好:
- MVC 让 UI 与 逻辑 解耦,这样 UI 组件更加单一,UI 组件专心处理样式,交互和终端兼容性问题即可。
- MVC 让 UI 与 逻辑 解耦,这样 UI 组件更容易被复用。就像上面的例子一样,这个组件的功能就是展示价格,不管这个价格是什么,那么所有需要展示价格的地方都能使用这个组件。但是如果没有 Controller 解耦,那 UI 组件就会变得非常臃肿,要传入更多的参数才能使用这个组件,复用度就会很低。
- 纯逻辑的代码更容易被单测,相对于 UI 组件来说。UI 和逻辑耦合严重的代码无法被单测。
- 纯逻辑可以被进一步拆分解耦,从而提升逻辑的复用度。上面的例子也展示了这一点,我们可以划分更细的 Controller,比如处理浮点数放大的 Controller、处理分期价格计算的 Controller 等等,而这些 Controller 也可以被其他场景复用。
在了解 MVC 的好处之后,让我们来看看,MVC 具体是怎么应用的。
后端服务中的 MVC

上面画了个简单的草图,现在后端流行微服务,基本上,每个后端服务都是一个简单的 MVC 架构:
- Model 层:主要是数据层,这些数据可以是从 DB 映射过来,也可以是从其他的数据源获取,也可以从另外一个服务请求过来。
- Controller 层:主要是逻辑层,负责处理 Model 层的数据,加工处理之后,返回给 View 层使用。
- View 层:现在的后端并不关心 UI 展示,这些都是由前端来做的,因此,对于后端来说,他们的 View 就是需要返回给前端的 Restful API 的数据。这是因为前后端分工而演变成现在这个样子的,在过去 (十几年前),前端还没那么流行的时候,后端开发是要把前端的活也干了的,他们在 Controller 层就要把页面拼接出来,当时比较流行的是 JSP,感兴趣的话可以去查一下了解。其实,对于我们前端来说,这个架构放在 Node 服务会更容易理解,我们的服务端渲染的服务,就是在 Controller 层把 HTML 文件的内容拼接出来,然后返回给浏览器。
后端的应用简单了解一下就好了,还是回到我们的正题,MVC 在前端领域中是怎样应用的呢?
前端领域的 MVC

实际上,当我们在开发页面的时候,应用 MVC 来设计我们的代码是比较合理的,这样设计的代码天然就更好被维护。
首先是 Model,我们可以把后端提供的数据接口看做 Model 层。当然,在一些大型应用中,逻辑异常复杂,数据繁多,很容易出现问题,因此,我们还会专门设计一层 Model 层,封装后端提供的原始数据,给页面应用提供统一规范的 Model 数据实体。
其次是 Controller,我们页面需要的核心逻辑,都应该抽离出来,成为一个个 Service 和 Controller。这些逻辑专门加工处理 Model 层的数据,转换成 UI 需要用到的数据。可以看到,这一层最核心的就是对数据的处理,比如如何触发数据的变更和数据的传递的。在这一层,有非常多的框架,比如 Redux/dva、Vuex、Mobx、zustand 等等。
最后是 View,也就是我们最常见的 UI 组件。当我们把逻辑从 UI 组件抽离出来之后,UI 组件就会变得纯粹,甚至有很多是静态组件,它们就更容易被复用。UI 组件最核心的职责就是如何把传入的数据正确地渲染到界面中,并跟用户进行交互。因此,View 层最核心要关注的是跟客户端打交道,比如前端开发接触最多的浏览器,我们要关注 HTML、CSS、DOM、BOM、浏览器兼容性、移动端响应式等等。在这一层,最出名的框架就是 React 和 Vue 了。
结语
就像之前的那个例子一样,太多的前端开发没有应用 MVC 思想去设计自己的代码,最终写出 MV 的代码,导致自己虽然使用了现代化的 UI 框架,强制实现了组件化,但那些组件都是不可复用,维护困难,一叠加功能就出问题。
究其本质,就是因为不理解 MVC 软件架构设计模式,并应用到自己的代码设计之中。
其实,MVC 思想并不复杂,它的核心就只是解耦,解耦 Model 和 View。只要你理解了这个核心,并多加练习,让它成为你的编码设计习惯,你就能写出高质量的代码。
其实,我们前端开发的日常工作就是 MVC:
- 获取数据 (Model),处理这些数据 (Controller),把加工后的数据展示到界面上 (View)。
- 另外一个方向是:捕获用户在界面上的交互行为 (View),这个交互对数据会产生什么影响 (Controller),把最新的数据提交给后端 (Model)。
了解这个 MVC 之后,就可以帮助你分类并理解后面需要学习的前端框架了:
- 有什么工具、方法、框架可以帮助我更好地获取各种格式的数据?定义这些数据?提交这些数据?
- 有什么框架、设计模式可以帮助我更好地维护大量地、各种格式的数据关系?让数据变更更加有序?让处理数据的逻辑更加解耦和可复用?
- 有什么框架、思想可以帮助我更高效地开发 UI 界面?帮我解决兼容性问题?
好啦,MVC 就讲到这里,希望你可以好好理解这个设计思想。接下来我们要学习的前端框架主要是以 View 层为主,Controller 层的框架也会涉及到一些,希望你可以更好地区分这些框架,明确它们的作用和应用领域。
----------------【END】----------------
如果你是真心喜欢前端,并相信成长,想要提升自己的话,欢迎加入之道前端学习圈子。
戳这里 免费获取 之道前端的学习资料和专属服务。
相关文章:
学前端框架之前,你需要先理解 MVC
MVC 软件架构设计模式鼎鼎大名,相信你已经听说过了,但你确定自己已经完全理解到 MVC 的精髓了吗? 如果你是新同学,没听过 MVC,那可以到网上搜一些文章来看看,不过你要有心理准备,那些文章大多都…...
Mysql:数据库
Mysql 一、数据库概念?二、MySQL架构三、SQL语句分类四、数据库操作4.1 数据库创建4.2 数据库字符集和校验规则4.3 数据库修改4.4 数据库删除4.4 数据库备份和恢复其他 五、表操作5.1 创建表5.2 修改表5.3 删除表 六、表的增删改查6.1 Create(创建):数据新增1&#…...
python的函数介绍
一.定义和调用函数 1.定义函数 在 Python 中,使用 def 关键字来定义一个函数。函数可以包含参数,也可以包含返回值 基本语法 def function_name(parameters):"""docstring"""# Function bodyreturn resultdef greet(n…...
要完成使用MLflow比较模型运行、选择模型并将其部署到REST API的教程
要完成使用MLflow比较模型运行、选择模型并将其部署到REST API的教程,请按照以下有序步骤操作: 设置环境 导出MLflow跟踪URI:设置环境变量以指向您的MLflow跟踪服务。export MLFLOW_TRACKING_URIyour-organizations-MLflow-server-url 加载数…...
Windows Docker笔记-简介摘录
Docker是一个开源的容器化平台,可以帮助开发人员将应用程序与其依赖项打包在一个独立的容器中,然后在任何安装的Docker的环境中快速、可靠地运行。 几个基本概念和优势: 容器:容器是一个轻量级、独立的运行环境,包含了…...
MVC 文件夹:架构之美与实际应用
MVC 文件夹:架构之美与实际应用 引言 MVC(Model-View-Controller)是一种设计模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种架构模式不仅提高了代码的可维护性和可扩展性,而且使得开发流程更加清晰。本文将深入探讨MVC文…...
AI透明化与全球政治格局的发展:如何避免AI被人为操控
在现代社会,人工智能(AI)已经逐渐渗透到我们的日常生活中,尤其是在社交平台和信息传播领域。虽然AI可以极大地推动社会发展,但也潜藏着被恶意操控的风险。最令人担忧的是,某些势力可能通过操控AI来操控公众…...
ubuntu 网络管理--wpa_supplicant、udhcpc
ubuntu 网络管理--wpa_supplicant 1 介绍wpa_supplicant 无线认证wpa_passphrase 配置工具 NetworkManager 网络管理udhcpc 与 dhclient对比dhclient概述主要功能 udhcpc概述主要功能 2 联系依赖关系配置文件 3 区别4 如何选择5 示例使用 wpa_supplicant 手动连接无线网络使用 …...
熟练掌握Http协议
目录 基本概念请求数据Get请求方式和Post请求方式 响应数据响应状态码 基本概念 Http协议全称超文本传输协议(HyperText Transfer Protocol),是网络通信中应用层的协议,规定了浏览器和web服务器数据传输的格式和规则 Http应用层协议具有以下特点&#…...
C++的 I/O 流
本文把复杂的基类和派生类的作用和关系捋出来,具体的接口请参考相关文档 C的 I/O 流相关的类,继承关系如下图所示 https://zh.cppreference.com/w/cpp/io I / O 的概念:内存和外设进行数据交互称为 I / O ,例如:把数…...
寒假刷题Day22
一、2570. 合并两个二维数组 - 求和法 class Solution { public:vector<vector<int>> mergeArrays(vector<vector<int>>& nums1, vector<vector<int>>& nums2) {int i 0, j 0, n1 nums1.size(), n2 nums2.size();int tmp 0;…...
【PDF多区域识别】如何批量PDF指定多个区域识别改名,基于Windows自带的UWP的文字识别实现方案
海关在对进口货物进行查验时,需要核对报关单上的各项信息。对报关单 PDF 批量指定区域识别改名后,海关工作人员可以更高效地从文件名中获取关键信息,如货物来源地、申报价值等。例如文件名 “[原产国]_[申报价值].pdf”,有助于海关快速筛选重点查验对象,提高查验效率和监管…...
【大数据技术】本机PyCharm远程连接虚拟机Python
本机PyCharm远程连接虚拟机Python 注意:本文需要使用PyCharm专业版。 pycharm-professional-2024.1.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本地PyCharm远程连接虚拟机,运行Python脚本,提高编程效率。 注意: …...
Windows图形界面(GUI)-QT-C/C++ - Qt Combo Box
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 一、概述 1.1 基本概念 1.2 应用场景对比 二、核心属性详解 2.1 行为控制 2.2 显示配置 三、数据操作与访问 3.1 基础数据管理 3.2 高级数据访问 四、用户交互处理 4.1 信号处…...
数字化转型:概念性名词浅谈(第四讲)
大家好,本篇文章是在新年之际写的,所以在这里先给大家拜个年。 今天要介绍的名词为ETL: ETL,是英文Extract-Transform-Load的缩写,用来描述将数据从来源端经过抽取(extract)、转换(transfor…...
标题:市场波动中的价格趋势分析与策略优化
在市场投资中,价格的波动不仅是常态,更是影响投资决策的关键因素。市场价格的变化受多种因素影响,包括供需关系、政策调整、国际市场动态等。如何理解价格走势,并在其中寻找合适的交易机会,是投资者需要长期研究的课题…...
【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(四) -> 常见组件(一)
目录 1 -> List 1.1 -> 创建List组件 1.2 -> 添加滚动条 1.3 -> 添加侧边索引栏 1.4 -> 实现列表折叠和展开 1.5 -> 场景示例 2 -> dialog 2.1 -> 创建Dialog组件 2.2 -> 设置弹窗响应 2.3 -> 场景示例 3 -> form 3.1 -> 创建…...
Linux:文件系统(软硬链接)
目录 inode ext2文件系统 Block Group 超级块(Super Block) GDT(Group Descriptor Table) 块位图(Block Bitmap) inode位图(Inode Bitmap) i节点表(inode Tabl…...
深度学习系列--01.入门
一.深度学习概念 深度学习(Deep Learning)是机器学习的分支,是指使用多层的神经网络进行机器学习的一种手法抖音百科。它学习样本数据的内在规律和表示层次,最终目标是让机器能够像人一样具有分析学习能力,能够识别文字…...
如何抓取酒店列表: 揭开秘密
搜索酒店列表是一种强大的工具,可以从各种在线资源中收集有关住宿、价格和可用性的综合数据。无论您是要比较价格、分析市场趋势,还是要创建个性化的旅行计划,搜索都能让您有效地汇编所需的信息。在本文中,我们将介绍如何搜索酒店…...
深度剖析 C++17 中的 std::byte:解锁字节级编程新境界
文章目录 一、引入背景二、基本定义三、特性详解不可隐式转换为整型显式转换为unsigned char位运算支持字面量支持四、使用场景内存操作数据序列化与反序列化网络通信文件读写操作五、与其他数据类型的交互与字符类型的交互与整数类型的交互与指针类型的交互六、注意事项避免混…...
【多线程】线程池核心数到底如何配置?
🥰🥰🥰来都来了,不妨点个关注叭! 👉博客主页:欢迎各位大佬!👈 文章目录 1. 前置回顾2. 动态线程池2.1 JMX 的介绍2.1.1 MBeans 介绍 2.2 使用 JMX jconsole 实现动态修改线程池2.2.…...
三维空间全局光照 | 及各种扫盲
Lecture 6 SH for diffuse transport Lecture 7关于 SH for glossy transport 三维空间全局光照 diffuse case和glossy case的区别 在Lambertian模型中,BRDF是一个常数 diffuse case 跟outgoing point无关 glossy case 跟outgoing point有关 (Gloss…...
通过C/C++编程语言实现“数据结构”课程中的链表
引言 链表(Linked List)是数据结构中最基础且最重要的线性存储结构之一。与数组的连续内存分配不同,链表通过指针将分散的内存块串联起来,具有动态扩展和高效插入/删除的特性。本文将以C/C++语言为例,从底层原理到代码实现,手把手教你构建完整的链表结构,并深入探讨其应…...
Polardb三节点集群部署安装--附虚拟机
1. 架构 PolarDB-X 采用 Shared-nothing 与存储计算分离架构进行设计,系统由4个核心组件组成。 计算节点(CN, Compute Node) 计算节点是系统的入口,采用无状态设计,包括 SQL 解析器、优化器、执行器等模块。负责数据…...
java s7接收Byte字节,接收word转16位二进制
1图: 2.图: try {List list getNameList();//接收base64S7Connector s7Connector S7ConnectorFactory.buildTCPConnector().withHost("192.168.46.52").withPort(102).withTimeout(1000) //连接超时时间.withRack(0).withSlot(3).build()…...
挑战项目 --- 微服务编程测评系统(在线OJ系统)
一、前言 1.为什么要做项目 面试官要问项目,考察你到底是理论派还是实战派? 1.希望从你的项目中看到你的真实能力和对知识的灵活运用。 2.展示你在面对问题和需求时的思考方式及解决问题的能力。 3.面试官会就你项目提出一些问题,或扩展需求…...
基于springboot的体质测试数据分析及可视化设计
作者:学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”,支持远程部署调试、运行安装。 项目包含: 完整源码数据库功能演示视频万字文档PPT 项目编码࿱…...
java-重载与重写
介绍 在 Java 中,重载(Overloading) 和 重写(Overriding) 是两个重要的概念,它们都与方法有关,但它们的应用场景和行为完全不同。 通过理解重载和重写的区别,可以更好地设计类的继承…...
使用C++构建一个优先级队列
1.优先级队列的介绍 优先级队列是一种特殊的队列数据结构,它是队列,但又不完全是,因为它要将装载的数据进行优先级排序,找到一个最大或者最小优先级的元素,下一次出队列的元素就是这个元素,所以说它不完全是…...
