框架通常只是一种设计模式的实现,它并不意味着你可以在开发中避免所有分层设计工作。
SPA 框架几乎都是基于 MVC 或 MVVM 设计模式而建立起来的,这些模式都只是宏观的分层设计,当代码量开始随着项目增大而增多时,问题就会越来越多。许多企业内部的项目仍然在使用 angularjs1.X ,你会发现许多 controller 的体积大到令人发指,稍有经验的团队会利用好 angularjs1 构建的 controller , service , filter 以及路由和消息机制来完成基本的拆分和解耦,这已经能让他们的开发能力中等体量的项目,往往只有掌握了 angularjs1 玩法精髓—— directive 的队伍,才能够在应付大型项目时使代码保持足够的清晰度,当然这只是在代码形态和模块划分上的工作,相当于代码的骨骼,想要让业务逻辑本身更加清晰,就需要更高级的建模设计知识来对业务逻辑进行分层,例如 领域驱动模型 。如果你仍然在使用 angularjs1.x 的版本进行开发,可以参考【如何重构Controller】进行基本的分层拆分设计。
有趣的是一些团队认为无法承载大型项目是 angularjs1.x 的原罪,与他们的开发水平无关,于是将希望寄托于拥有自动化工具加持的现代化 SPA 框架,然而如果有机会观察你就会发现,许多项目对新框架的使用方式和之前并没有本质的差别,只不过是把以前臃肿到不行的代码又换了一种形式塞进了前端工程里,然后借着 ES6 语法和新型框架本身的简洁性,开始沾沾自喜地认为这是自己重构的功劳。
请记住,如果不进行结构设计,即便使用最新版本的最热门的框架,写出来的代码依旧会是一团乱麻。
二. Vue开发中的script拆分优化
以 Vue 框架为例,在工程化工具和 vue-loader 的支撑下,主流的开发模式是基于 *.vue 这种单文件组件形态的。一个典型的 vue 组件包含如下几个部分:
<template> <!--视图模板--> </template> <script> /*编写组件脚本*/ export default { name:'component1' } </script> <style> /*编写组件样式*/ </style>
script 的部分通常包含有 交互逻辑 , 业务逻辑 , 数据转换 以及 DOM操作 ,如果不加整理,很容易变得混乱不堪。 *.vue 文件的本质是View层代码,它应该尽可能轻量并包含与视图有关的信息,即 特性声明 和 事件分发 ,其他的代码理论上都应该剥离出去,这样当项目体量增大后,维护起来就更容易聚焦关键信息,下面就如何进行脚本代码拆分提供一些思路,有一些可能是很基本的原则,为尽可能完整就放在一起,你并不需要从最开始就采纳所有的建议。
1.组件划分
这是View层减重的基础,将可共用的视图组件剥离出去,改为消息机制进行通信,甚至直接剥离出包含视图和业务代码的业务逻辑组件,都可以有效地拆分View层,降低代码的复杂度。
2.剥离业务逻辑代码
script 中最大的一部分一般是业务逻辑,首先将业务逻辑代码剥离为独立的 [name].business.js 模块,这样做的直观好处就是减轻了View层,另一方面是解除了业务逻辑和页面之间的强绑定关系,如果其他页面也涉及到这块业务逻辑中的个别方法,就可以直接进行复用,最后就是当项目逐渐复杂,你决定引入 vuex 来进行状态管理时View层会相对更容易修改。
一段包含基本增删改查逻辑的组件大概是下面的样子:
<script> export default{ name:'XXX', methods:{ handleClickCreate(){}, handleClickEdit(){}, handleClickRefresh(){}, handleClickDelete(){}, sendCreate(){}, sendEdit(){}, sendGetAll(){}, sendDelete(){} } } </script>
简易的剥离方式是将交互逻辑保留在视图层,将业务逻辑部分代码放在另一个模块中,然后利用 ES6 扩展运算符将其加入到组件实例的方法中,如下所示:
<script> import OrderBusiness from './Order.business.js'; export default{ name:'XXX', methods:{ ...OrderBusiness, handleClickCreate(){}, handleClickEdit(){}, handleClickRefresh(){}, handleClickDelete(){}, } } </script>
这种方式只是一种形态上的模块化拆分,并没有对业务逻辑本身进行梳理。另一种方式是构建独立的业务逻辑服务,保留在View层中的代码很容易转换为使用 vuex 时的编码风格:
<script> import OrderBusiness from './Order.business.js'; export default{ name:'XXX', methods:{ handleClickCreate(){ OrderBusiness.sendCreate(); }, handleClickEdit(){ OrderBusiness.sendEdit(); }, handleClickRefresh(){ OrderBusiness.sendGetAll(); }, handleClickDelete(){ OrderBusiness.sendDelete(); } } } </script>
笔者的建议是,前面三个示例随着项目体量的增长可以实现渐进式的修改。
3. 剥离数据转换代码