Vue DevUI 是一个社区共建的开源组件库,为了确保一致性和质量,需要所有参与 Vue DevUI 建设的贡献者都遵循同一份开发规范。
规范分成以下几个部分:
- 组件目录和文件组织规范
- 组件 API 和 Demo 设计规范
- 组件 API 和 Demo 文档规范
- 组件编码规范
组件目录和文件组织规范
Vue DevUI 包含丰富的组件,都在devui-vue
子包的devui
目录下,该目录下的每一个子目录都是一个组件的源码,每个组件都有一个或多个贡献者。
组件目录和文件组织规范的目的就是规范组件的目录结构和各组件文件的组织形式。
目录规范分成以下部分:
- 组件目录结构
- 入口文件
index.ts
- 组件文件
my-component.tsx
- 类型文件
my-component-types.ts
- Composable
use-my-composable.ts
- 样式文件
my-component-scss
- 单元测试文件
my-component.spec.ts
组件目录结构[#]
以下是组件目录结构的基本模板
my-component
├── __tests__ // 单元测试
| └── my-component.spec.ts
├── index.ts // 入口文件
└── src // 组件源码
└── components // 子组件
├── my-sub-component.ts
└── composables // 组件的逻辑部分 composable
├── my-use-composable.ts
├── my-component-types.ts // 组件类型
├── my-component.scss // 组件样式
└── my-component.tsx // 组件
入口文件 index.ts
import type { App } from 'vue';
import MyComponent from './src/my-component';
export * from './src/my-component-types';
export { MyComponent };
export default {
title: 'MyComponent 我的组件',
category: '通用',
status: '100%',
install(app: App): void {
app.component(MyComponent.name, MyComponent);
},
};
组件文件 my-component.tsx
import { defineComponent, toRefs } from 'vue';
import type { SetupContext } from 'vue';
import { myComponentProps, MyComponentProps } from './my-component-types';
import useMyComposable from './composables/use-my-composable';
import './my-component.scss';
export default defineComponent({
name: 'DMyComponent',
props: myComponentProps,
emits: ['update:modelValue'],
setup(props: MyComponentProps, ctx: SetupContext) {
const { myProp } = toRefs(props);
const { myUseVar, myUseMethod } = useMyComposable(myUseParam);
return () => {
return (
<div class="devui-my-component">{ myProp.value }</div>
);
};
},
});
类型文件 my-component-types.ts
import { PropType, ExtractPropTypes } from 'vue';
export const myComponentProps = {
myProp: {
type: Number,
default: 1
},
myProp2: {
type: Array as PropType<number[]>,
default: [5, 10, 20, 50]
},
} as const;
export type MyComponentProps = ExtractPropTypes<typeof myComponentProps>;
Composable use-my-composable.ts
import { ref } from 'vue';
export default function useMyComposable(myUseParam) {
const myUseVar = ref(xxx);
const myUseMethod = () => {
};
return { myUseVar, myUseMethod };
}
样式文件 my-component-scss
@import '../../styles-var/devui-var.scss';
.devui-my-component {
}
单元测试文件 my-component.spec.ts
import { mount, DOMWrapper } from '@vue/test-utils';
import { ref } from 'vue';
import DMyComponent from '../src/my-component';
describe('MyComponent', () => {
it('should render correctly', async () => {
const wrapper = mount({
components: { DMyComponent },
template: `
<d-my-component my-prop="xxx" />
`,
setup() {
const myVar = ref(xxx);
return { myVar };
}
});
expect(xxx).toEqual(xxx);
});
});
组件 API 和 Demo 设计规范
- 命名方式用中划线风格:组件的参数名和事件名统一使用中划线格式。
- 组件名称前缀:组件的命名统一使用D前缀。
- 针对需要双向绑定的参数,需要直接用v-model,避免增加额外参数,例如v-model:xxx。
- 原生支持的属性尽量不再用API去单独声明,直接通过attrs透传即可,比如placeholder。
组件 API 和 Demo 文档规范
Demo 文档
- 演示demo需要对所使用的API及组件默认行为和样式等进行尽可能详细的说明。避免让用户自己去推测,降低用户学习和使用成本。
- 每个组件的第一个demo,应该是组件最基本的用法,即展示组件在不传参数或者传入最基本参数情况下的效果。后面的demo应该尽可能按照参数的使用频率来排序。
- 每个demo所展示的API应该尽量精简,尽量不要一个demo中展示多个API的用法。
- 当API是枚举值时,demo中应尽量展示每个枚举值的效果。
- 演示demo代码,组件的参数大于三个或单行过长时需要每个参数占用一行来展示,避免出现横向滚动条,。
- 演示demo自定义class样式,命名格式为xxx-demo-yyy(xxx为组件名,yyy为自定义样式名),不然会成为全局样式,有可能影响其他组件或者demo效果。
- 文案描述需清晰,尽量参考ng devui的文案描述,尽量避免口语化;标点符号使用需正确;文案中若涉及到英文单词,需在单次左右两侧加一个空格。
- 一个标题尽量展示一个demo,避免一个标题中展示多个demo。
- boolean类型的参数,在demo中展示,设置为true的时候,不需要显式的设置为true,直接写参数名字即可。
- demo的描述说明文案中,用到代码块的地方需要用反引号包裹。
- demo的描述说明文案应该跟在:::demo后面,不应该放在h4或其他标签中,也不应该放在代码块外面。
- 【何时使用】标题等级应该为四级,避免出现在快速前往导航中。
API 文档
- API部分应该遵循参数、事件、方法、插槽、类型定义的顺序,若某一项缺失则跳过;如果组件有特殊项需要说明,需要在类型定义后面编写。
- API表格的标题,组成格式为:Xxx [参数 | 事件 | 方法 | 插槽],Xxx为组件名字,采用大驼峰书写,需要注意组件名字后面加一个空格,标题等级为三级;类型定义标题的格式为Xxx 类型定义,组件名字同样为大驼峰格式,中间同样需要加一个空格,标题等级同样为三级,具体类型名字跟随在后面用四级标题定义。
- API表格表头和内容应该左对齐。
- 参数表格需要具备的列名及顺序为:参数名、类型、默认值、说明、跳转Demo。
- 参数不需要使用反引号。
- 类型需要使用反引号包裹;类型需准确,简单枚举值类型可直接列出来,复杂一些的类型可以写类型名字(如SizeType),然后增加锚点定位;参数基本类型采用首字母小写string,自定义类型名字采用大驼峰命名,(如SizeType)。
- 默认值不需要反引号包裹,如果默认值为字符串或者枚举类型,应该使用单引号包裹,若无默认值则用双横线--表示。
- 说明中需要标注该参数为必选还是可选。
- 跳转Demo中的链接需能够正确跳转,并且demo中需要展示对应API的用法;若无展示Demo,则空白展示。
- 事件表格需要具备的列名及顺序为:事件名、回调参数、说明、跳转Demo。
- 事件名不需要使用反引号。
- 回调参数需要使用反引号包裹;类型格式为Function(name: string)。
- 跳转Demo中的链接需能够正确跳转,并且demo中需要展示对应API的用法;若无展示Demo,则空白展示。
- 方法表格需要具备的列名及顺序为:方法名、类型、说明。
- 方法名不需要使用反引号。
- 类型需要使用反引号包裹。
- 插槽表格需要具备的列名及顺序为:插槽名、说明、参数。
- 默认插槽也需要做说明,并且插槽名字应该为default。
- 参数为组件内部暴露出来的数据。
- 类型定义需要使用typescript代码块,代码块格式为type xxx = yyy。
组件编码规范
- 安装VSCode插件CodeMetrics,原则上函数圈复杂度不超过20。
- 正确定义和使用TS类型,代码无TS类型报错。
- 变量采用语义化命名,原则上不需要通过注释说明变量或函数功能。
- 需注意逻辑和结构的拆分,原则上函数不应该超过50行。
- 目录下的子目录和文件数之和不超过10个。
- 原则上单个文件的代码行数不超过200行。
- 代码单行长度不超过140个字符。
- 代码块嵌套深度不超过4层。
- 组件props需在xx-types.ts文件中定义,并且导出相关参数和props的类型。
- 代码中不应该出现未使用的变量和依赖。
- 代码中不应该出现console等调试信息。
- 在setup函数返回的render函数中定义组件的DOM结构,而不是用单独的render函数来定义。
- 需要在组件的index.ts文件导出组件参数的类型,方便业务在使用组件时,利用组件导出的参数类型。
- 组件的import列表大致遵循以下几个原则:
- 最上面应该是依赖的三方库,例如vue;中间部分是依赖的组件库的类型文件、子组件、工具函数等;最后一部分是依赖的样式。
- 对于同一个库中的依赖,按照字典序排列,比如vue依赖中的defineComponent需要排在ref前面。
- 中间部分的引入顺序为类型文件、子组件、工具函数。
- 需要区分从vue中引入的api和类型,对于类型的引入,需要通过import type引入,例如import type { Ref } from 'vue',类型引入应该紧跟在api引入的后面。
- defineComponent参数顺序为name、props、emits、inheritAttrs、setup。components和directives不需要在组件内显示声明。
- 变量和函数的声明顺序需要按照字典序排列。