当一个 Vue 项目源文件达到 400 以上时,发现开发起来已经显得有些臃肿,本文就在多个方面进行一些模块化的尝试。
更低程度的模块化
通常 CLI 生成的项目结构都比较简单,易于上手。一般来说都会安装 Vuex、Vue Router 包进行配合开发,他们的默认结构大体是这样的:
1 2 3 4 5 6
| ├── App.vue ├── assets ├── main.js ├── pages ├── router └── store
|
在小型项目中,开发完全没有问题,即使大型项目也是可以继续开发的,但是我们会发现一些问题,比如:
- router 中的 router.js 路由文件越来越大,十分复杂
- store 中管理非常多的状态,混乱度增加
- pages 主要业务文件夹中,页面列表越来越长,业务内聚力差
在业务成长一定程度后,基调必定会确定下来,通过分析思考,我们可以在业务里提取出模块。例如:
1 2 3 4 5 6 7 8 9 10
| ├── App.vue ├── assets ├── main.js ├── modules # 原pages │ ├── Business │ ├── Device │ ├── Search │ └── ... ├── router └── store
|
在此基础上,将 router 和 store 的配置,下放到每一个 module 去。这样主目录下的 router 和 store 都会变得比较简单。而在每个 module 中,router 和 store 都更密切的关联该模块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ├── App.vue ├── assets ├── main.js ├── modules # 原pages │ ├── Business │ │ ├── pages │ │ ├── index.js │ │ ├── router.js │ │ └── store.js │ ├── Device │ ├── Search │ └── ... ├── router └── store
|
视图、业务逻辑分离
Vue 快速开发的特色之一,就是在单一的一个 vue 文件中,可以写入 template、js 和 css,开发者不需要切换多个页面。但是在大型的表单类页面中,需求上设计的就非常复杂,不考虑各种优化的情况下,页面代码量可能达到 1000 行以上,在这种页面中进行修改和增加新的代码极容易出现问题。
当然,解决方案之一是组件化,但是对于表单来说,整个表单就是多个组件组合而成,而且本身表单组件也复杂,所以组件化只能解决部分问题。
这里我提出的方案,灵感来自于 AngularJS 的文件结构和 Vue Router 中的mapActions
方法:
1 2 3
| user ├── index.vue └── index.service.js
|
将部分复杂的逻辑,抽取到index.service.js
中,如何引入到index.vue
中呢?
非常简单:
File: index.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template>
</tempate> <script> import mapServices from '@/utils/service.js' import service from './index.service.js'
export default { created() { this.fetchData() }, methods: { ...mapServices(service)([ 'login', 'logout' 'register', 'fetchData' ]) } } </script>
|
File: index.service.js
1 2 3 4 5 6 7 8 9 10 11
| function login() {} function logout() {} function register() {} function fetchData() {}
export default { login, logout, register, fetchData, };
|
File: @/utils/service.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| export default function mapServices(services) { if (!services) { return () => {}; }
return (props) => { if (!Array.isArray(props)) { throw new Error("mapServices only accept an Array"); }
let funcs = {}; props.forEach((propName) => { services[propName] && (funcs[propName] = services[propName]); }); return funcs; }; }
|
这种方式即可将逻辑分散到其他文件中,并在 vue 主文件中,也不失关联性的,能够自然开发。