基础规范
项目命名
全部采用小写方式, 以中划线分隔。
1 2
| 正例:`smart-admin` 反例:`mall_management-system / mallManagementSystem`
|
目录、文件命名
目录、文件名 均以 小写方式, 以中划线分隔。
1 2
| 正例:`/head-search/`、`/shopping-car/`、`smart-logo.png`、`role-form.vue` 反例:`/headSearch/`、 `smartLogo.png`、 `RoleForm.vue`
|
单引号、双引号、分号
Vue3 组合式 API 规范
使用 setup 语法糖
组件必须使用 setup 语法糖
setup 大法方便简洁
全局都要使用 setup 语法糖
组合式 Composition API 规范
组件内必须使用模块化思想,把代码进行拆分;参照 vue3 官方文档对于 Composition Api 的理解: 更灵活的代码组织 (opens new window),组合式 Api,即 Composition API 解决的是让 相互关联的代码在一起,以更方便的组织代码,故我们的代码格式如下:
即:将相关的 变量和代码 写到一起,并使用 行注释 进行分块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script setup>
import xxxxx; import xxxxx; import xxxxx;
</script>
|
举例,分成了两个模块,即:
模块1:显示 、隐藏操作的 变量和方法
模块2:表单的 变量和方法
【以下是正确的例子】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| <script setup> import { ref, reactive } from 'vue'; import { message } from 'ant-design-vue'; import { SmartLoading } from '/@/components/framework/smart-loading'; import _ from 'lodash'; import { categoryApi } from '/@/api/business/category/category-api'; import { smartSentry } from '/@/lib/smart-sentry';
const emit = defineEmits('reloadList');
const formRef = ref();
const visible = ref(false); function showModal(categoryType, parentId, rowData) { Object.assign(form, formDefault); form.categoryType = categoryType; form.parentId = parentId; if (rowData && !_.isEmpty(rowData)) { Object.assign(form, rowData); } visible.value = true; } function onClose() { Object.assign(form, formDefault); visible.value = false; }
const formDefault = { categoryId: undefined, categoryName: '', categoryType: 1, parentId: undefined, disabledFlag: false, }; let form = reactive({ ...formDefault }); const rules = { categoryName: [{ required: true, message: '请输入分类名称' }], };
function onSubmit() { formRef.value .validate() .then(async () => { SmartLoading.show(); try { if (form.categoryId) { await categoryApi.updateCategory(form); } else { await categoryApi.addCategory(form); } message.success(`${form.categoryId ? '修改' : '添加'}成功`); emit('reloadList', form.parentId); onClose(); } catch (error) { smartSentry.captureError(error); } finally { SmartLoading.hide(); } }) .catch((error) => { console.log('error', error); message.error('参数验证错误,请仔细填写表单数据!'); }); }
defineExpose({ showModal, }); </script>
|
模板引用变量 Ref
对于 vue3 中的模板引用 ref,即 ref 是作为一个特殊的 attribute
我们要求:
比如上面的例子,我们声明如下
变量和方法的注释
在使用 Composition Api 进行代码编写时,我们有效的组织了代码,但是由于 Composition Api 变量和方法会写到一起,这时候注释就变得很有必要 要求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const queryFormState = { noticeTypeId: undefined, keywords: '', documentNumber: '', createUserId: undefined, deletedFlag: undefined, createTimeBegin: null, createTimeEnd: null, publishTimeBegin: null, publishTimeEnd: null, pageNum: 1, pageSize: PAGE_SIZE, };
const queryForm = reactive({ ...queryFormState });
|
Vue3 组件规范
组件文件名
组件文件名应该为 pascal-case 格式
正例:
1 2
| components |- my-component.vue
|
反例:
1 2 3
| components |- myComponent.vue |- MyComponent.vue
|
父子组件文件名
和父组件紧密耦合的子组件应该以父组件名作为前缀命名 正例:
1 2 3 4 5
| components |- todo-list.vue |- todo-list-item.vue |- todo-list-item-button.vue |- user-profile-options.vue (完整单词)
|
反例:
1 2 3 4 5
| components |- TodoList.vue |- TodoItem.vue |- TodoButton.vue |- UProfOpts.vue (使用了缩写)
|
组件属性
组件属性较多,应该主动换行。
正例:
1 2 3 4
| <MyComponent foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" />
|
反例:
1
| <MyComponent foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c"/>
|
模板中表达式
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
正例:
1 2 3 4 5 6 7 8 9 10 11 12
| <template> <p>{{ normalizedFullName }}</p> </template>
computed: { normalizedFullName: function () { return this.fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') } }
|
反例:
1 2 3 4 5 6 7 8 9
| <template> <p> {{ fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') }} </p> </template>
|
标签顺序
单文件组件应该总是让标签顺序保持为 <template> 、<script>、 <style>
正例:
1 2 3
| <template>...</template> <script>...</script> <style>...</style>
|
反例:
1 2 3
| <template>...</template> <style>...</style> <script>...</script>
|
Vue Router 规范
页面传参
页面跳转,例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B 页面,推荐使用 路由参数进行传参,即 {query:param}
正例:
1 2
| let id = ' 123'; this.$router.push({ name: 'userCenter', query: { id: id } });
|
path 和 name 命名规范
pathkebab-case 命名规范(尽量与 vue 文件的目录结构保持一致,因为目录、文件名都是 kebab-case,这样很方便找到对应的文件)
path 必须以 / 开头,即使是 children 里的 path 也要以 / 开头。如下示例
经常有这样的场景:某个页面有问题,要立刻找到这个 vue 文件,如果不用以/开头,path 为 parent 和 children 组成的,可能经常需要在 router 文件里搜索多次才能找到,而如果以/开头,则能立刻搜索到对应的组件
name 命名规范采用 KebabCase 命名规范且和 component 组件名保持一致!(因为要保持 keep-alive 特性,keep-alive 按照 component 的 name 进行缓存,所以两者必须高度保持一致)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| export const reload = [ { path: '/reload', name: 'reload', component: Main, meta: { title: '动态加载', icon: 'icon iconfont' },
children: [ { path: '/reload/smart-reload-list', name: 'SmartReloadList', meta: { title: 'SmartReload', childrenPoints: [ { title: '查询', name: 'smart-reload-search' }, { title: '执行reload', name: 'smart-reload-update' }, { title: '查看执行结果', name: 'smart-reload-result' } ] }, component: () => import('@/views/reload/smart-reload/smart-reload-list.vue') } ] } ];
|
Vue 项目规范
目录规范
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| src 源码目录 |-- api 所有api接口 |-- assets 静态资源,images, icons, styles等 |-- components 公用组件 |-- config 配置信息 |-- constants 常量信息,项目所有Enum, 全局常量等 |-- directives 自定义指令 |-- i18n 国际化 |-- lib 外部引用的插件存放及修改文件 |-- mock 模拟接口,临时存放 |-- plugins 插件,全局使用 |-- router 路由,统一管理 |-- store vuex, 统一管理 |-- theme 自定义样式主题 |-- utils 工具类 |-- views 视图目录 | |-- role role模块名 | |-- |-- role-list.vue role列表页面 | |-- |-- role-add.vue role新建页面 | |-- |-- role-update.vue role更新页面 | |-- |-- index.less role模块样式 | |-- |-- components role模块通用组件文件夹 | |-- employee employee模块
|
api 目录
api 文件要以 api 为结尾,比如 employee-api.js、login-api.js,方便查找
api 文件必须导出对象必须以 Api 为结尾,如:employeeApi、noticeApi
api 中以一个对象将方法包裹
api 中的注释,必须和后端 swagger 文档保持一致,同时保留后端作者
正例:
前端: department-api.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import { getRequest, postRequest } from '/@/lib/axios';
export const departmentApi = {
queryAllDepartment: () => { return getRequest('/department/listAll'); },
queryDepartmentTree: () => { return getRequest('/department/treeList'); },
addDepartment: (param) => { return postRequest('/department/add', param); },
updateDepartment: (param) => { return postRequest('/department/update', param); } };
|
assets 目录
assets 为静态资源,里面存放 images, styles, icons 等静态资源,静态资源命名格式为 kebab-case
1 2 3 4 5 6
| |assets |-- icons |-- images | |-- background-color.png | |-- upload-header.png |-- styles
|
components 目录
此目录应按照组件进行目录划分,目录命名为 kebab-case,一个组件必须一个单独的目录 ;
举例如下:
1 2 3 4 5 6 7 8
| |components |-- error-log | |-- index.vue | |-- index.less |-- markdown-editor | |-- index.vue | |-- index.js |-- kebab-case
|
constants 目录
此目录存放项目所有常量和枚举。
具体要求:
常量文件要以 const 为结尾,比如login-const.js、file-const.js
变量要:大写下划线,比如 LOGIN_RESULT_ENUM、LOGIN_SUCCESS、LOGIN_FAIL
如果是 枚举,变量必须以 ENUM为结尾,如:LOGIN_RESULT_ENUM、CODE_FRONT_COMPONENT_ENUM
目录结构:
1 2 3 4
| |constants |-- index-const.js |-- role-const.js |-- employee-const.js
|
例子: employee-const.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| export const EMPLOYEE_STATUS = { NORMAL: { value: 1, desc: '正常' }, DISABLED: { value: 1, desc: '禁用' }, DELETED: { value: 2, desc: '已删除' } };
export const EMPLOYEE_ACCOUNT_TYPE = { QQ: { value: 1, desc: '短信登陆' }, WECHAT: { value: 2, desc: '微信登录' }, DINGDING: { value: 3, desc: '钉钉登录' }, USERNAME: { value: 4, desc: '用户名密码登录' } };
export default { EMPLOYEE_STATUS, EMPLOYEE_ACCOUNT_TYPE };
|
router 与 store 目录
这两个目录一定要将业务进行拆分,不能放到一个 js 文件里。
router 尽量按照 views 中的结构保持一致
store 按照业务进行拆分不同的 js 文件
views 目录
目录要求,按照模块划分,其中具体文件名要求如下:
如果是列表页面,要以list为结尾,如 role-list.vue、cache-list.vue
如果是 表单页面,要以 form为结尾,如 role-form.vue、notice-add-form.vue
如果是 modal弹窗,要以 modal为结尾,如 表单弹窗 role-form-modal.vue,详情 role-detail-modal.vue
如果是 drawer 抽屉页面,要同上以 Drawer为结尾
1 2 3 4 5 6 7 8 9 10 11
| |-- views 视图目录 | |-- role role模块名 | | |-- role-list.vue role列表页面 | | |-- role-add-form.vue role新建页面 | | |-- role-update-form-modal.vue role更新页面 | | |-- index.less role模块样式 | | |-- components role模块通用组件文件夹 | | | |-- role-title-modal.vue role弹出框组件 | |-- employee employee模块 | |-- behavior-log 行为日志log模块 | |-- code-generator 代码生成器模块
|