165 lines
5.3 KiB
Markdown
165 lines
5.3 KiB
Markdown
|
# Farris UI Vue 组件开发规范
|
|||
|
|
|||
|
为了保证 Farris UI Vue 的源代码风格一致,确保组件研发质量,方便社区开发者阅读代码参与贡献,需要所有参与Farris UI Vue 组件开发的贡献,都要遵循此组件开发规范。
|
|||
|
|
|||
|
|
|||
|
## 组件目录和文件规范
|
|||
|
|
|||
|
Farris UI Vue 的组件,都包含在`ui-vue`包的`components`目录下,每一个子组件为独立目录,目录名为全小写的组件名,当组件名包含多个英文单词时,使用`-`分隔。
|
|||
|
|
|||
|
目录规范分成以下部分:
|
|||
|
|
|||
|
### 组件目录结构
|
|||
|
|
|||
|
以下是单个组件目录的结构
|
|||
|
|
|||
|
```
|
|||
|
input-group
|
|||
|
├── test // 单元测试
|
|||
|
| └── input-group.spec.tsx
|
|||
|
├── src // 组件源码
|
|||
|
| ├── components // 子组件
|
|||
|
| | └── input-group-sub.component.tsx
|
|||
|
| ├── composition // 组件的可复用逻辑
|
|||
|
| | ├── types.ts // 组合式Api返利值接口类型
|
|||
|
| | ├── use-append-button.ts // 实现组件特性1的组合式Api
|
|||
|
| | └── use-clear.ts // 实现组件特性2的组合式Api
|
|||
|
| ├── input-group.component.tsx // 组件代码
|
|||
|
| └── input-group.props.ts // 定义组件Api
|
|||
|
└── index.ts // 组件入口文件
|
|||
|
```
|
|||
|
|
|||
|
### 入口文件 `index.ts`
|
|||
|
|
|||
|
```TypeScript
|
|||
|
import type { App } from 'vue';
|
|||
|
import InputGroup from './src/input-group.component';
|
|||
|
|
|||
|
export * from './src/input-group.props';
|
|||
|
|
|||
|
export { InputGroup };
|
|||
|
|
|||
|
export default {
|
|||
|
install(app: App): void {
|
|||
|
app.component(InputGroup.name, InputGroup);
|
|||
|
},
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
### 组件文件 `input-group.component.tsx`
|
|||
|
|
|||
|
```TypeScript
|
|||
|
import { defineComponent, toRefs } from 'vue';
|
|||
|
import type { SetupContext } from 'vue';
|
|||
|
|
|||
|
import { InputGroupProps, inputGroupProps } from './input-group.props';
|
|||
|
import { useClear } from './composition/use-clear';
|
|||
|
|
|||
|
export default defineComponent({
|
|||
|
name: 'FInputGroup',
|
|||
|
props: inputGroupProps,
|
|||
|
emits: ['update:modelValue'],
|
|||
|
setup(props: InputGroupProps, setupContext: SetupContext) {
|
|||
|
const { someProp } = toRefs(props);
|
|||
|
const { showClearButton, onClearValue } = useClear();
|
|||
|
|
|||
|
return () => {
|
|||
|
return (
|
|||
|
<div class="f-input-group">{ someProp.value }</div>
|
|||
|
);
|
|||
|
};
|
|||
|
},
|
|||
|
});
|
|||
|
```
|
|||
|
|
|||
|
### 类型文件 `input-group.props.ts`
|
|||
|
|
|||
|
```TypeScript
|
|||
|
import { PropType, ExtractPropTypes } from 'vue';
|
|||
|
|
|||
|
export const inputGroupProps = {
|
|||
|
/**
|
|||
|
* 显示输入框的标签
|
|||
|
*/
|
|||
|
enableTitle: { type: Boolean, default: false },
|
|||
|
/**
|
|||
|
* 输入框提示文本
|
|||
|
*/
|
|||
|
placeholder: { type: String, default: '' },
|
|||
|
/**
|
|||
|
* 输入框Tab键索引
|
|||
|
*/
|
|||
|
tabIndex: Number
|
|||
|
};
|
|||
|
|
|||
|
export type InputGroupProps = ExtractPropTypes<typeof inputGroupProps>;
|
|||
|
```
|
|||
|
|
|||
|
### 组合式Api `use-clear.ts`
|
|||
|
|
|||
|
```TypeScript
|
|||
|
import { computed, SetupContext } from 'vue';
|
|||
|
import { InputGroupProps } from '../input-group.props';
|
|||
|
import { UseClear } from './types';
|
|||
|
|
|||
|
export function useClear(props: InputGroupProps, setupContext: SetupContext): UseClear {
|
|||
|
const showClearButton = computed(() => props.enableClear && !props.readonly && !props.disable);
|
|||
|
|
|||
|
function onClearValue($event: Event) {
|
|||
|
console.log('on onClearValue');
|
|||
|
}
|
|||
|
|
|||
|
return {
|
|||
|
showClearButton,
|
|||
|
onClearValue
|
|||
|
};
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### 单元测试 `input-group.spec.tsx`
|
|||
|
|
|||
|
```ts
|
|||
|
import { mount } from '@vue/test-utils';
|
|||
|
import { InputGroup } from '..';
|
|||
|
|
|||
|
describe('f-input-group', () => {
|
|||
|
it('variant', () => {
|
|||
|
const wrapper = mount({
|
|||
|
setup() {
|
|||
|
return () => {
|
|||
|
return <InputGroup editable={false}></InputGroup>;
|
|||
|
};
|
|||
|
},
|
|||
|
});
|
|||
|
|
|||
|
expect(wrapper.find('.f-cmp-inputgroup').exists()).toBeTruthy();
|
|||
|
expect(wrapper.find('div').find('div').find('input').find('[readlony]').exists).toBeTruthy();
|
|||
|
});
|
|||
|
});
|
|||
|
```
|
|||
|
|
|||
|
## 组件编码规范
|
|||
|
|
|||
|
- 组件采用中划线风格命名,组件的参数名和事件名统一使用中划线格式。
|
|||
|
- 所有组件统一在名称前使用`F`前缀,组件选择器前使用`f-`前缀。
|
|||
|
- 直接用v-model传递双向绑定的参数。
|
|||
|
- 使用属性透传传递原生属性,不允许在单独定义API声明原生属性。
|
|||
|
- 正确定义和使用TypeScript类型,代码中无TypeScript类型报错。
|
|||
|
- 变量采用语义化命名,原则上不需要通过注释说明变量或函数功能,详细命名规则参考[Farris UI TypeScript 编码指南](./style-guid/typescript_style_guid.md)。
|
|||
|
- 需要将组件的props定义在独立的文件some-component.props.ts文件中,并在此文件中同时导出props和PropsType。
|
|||
|
- 应该在setup函数返回的render函数中编写组件的Html模板。
|
|||
|
- 必须在组件的index.ts文件中导出组件参数的类型,以便于在引用组件时,方便TypeScript进行类型提示。
|
|||
|
- defineComponent函数接收的参数顺序为name、props、emits、inheritAttrs、setup。
|
|||
|
- 不要在组件内显式声明components和directives。
|
|||
|
- 需要安装字典顺序排列组件的变量。
|
|||
|
|
|||
|
|
|||
|
## 组件文档规范
|
|||
|
|
|||
|
待上线Doc站点后补充
|
|||
|
|
|||
|
|
|||
|
## 关于
|
|||
|
本项目的 Farris UI Vue 组件开发规范遵循[CC-By 3.0协议](https://creativecommons.org/licenses/by/3.0/)。
|
|||
|
|
|||
|
<a rel="license" href="https://creativecommons.org/licenses/by/3.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/3.0/88x31.png" /></a>
|