学前端框架之前,你需要先理解 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】----------------
如果你是真心喜欢前端,并相信成长,想要提升自己的话,欢迎加入之道前端学习圈子。
戳这里 免费获取 之道前端的学习资料和专属服务。