@qxs-bns/components
v0.0.88
Published
Vue 3 Component Library
Readme
@qxs-bns/components
QXS Business System 组件库,基于 Vue 3 + TypeScript + Element Plus 构建的企业级组件库。
✨ 特性
- 🎯 企业级 - 专为企业级应用设计,提供丰富的业务组件
- 🔧 二次封装 - 基于 Element Plus 进行增强,保持 API 一致性
- 📦 按需加载 - 支持 Tree-shaking,减少打包体积
- 🎨 主题定制 - 支持主题定制和暗黑模式
- 🌍 国际化 - 内置国际化支持
- 📱 响应式 - 移动端友好的响应式设计
- ♿ 无障碍 - 遵循 WAI-ARIA 标准
- 🎪 TypeScript - 完整的 TypeScript 类型定义
📦 安装
# npm
npm install @qxs-bns/components
# yarn
yarn add @qxs-bns/components
# pnpm
pnpm add @qxs-bns/components🚀 快速开始
完整引入
import { createApp } from 'vue'
import QxsComponents from '@qxs-bns/components'
import '@qxs-bns/components/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(QxsComponents)
app.mount('#app')按需引入
<template>
<QxsButton type="primary">按钮</QxsButton>
<QxsDataChart :data="chartData" show-type-name="bar" />
</template>
<script setup>
import { QxsButton, QxsDataChart } from '@qxs-bns/components'
const chartData = {
data: [
{ name: '一月', value: 100 },
{ name: '二月', value: 200 }
]
}
</script>🏗️ 项目结构
packages/components/
├── src/ # 源码目录
│ ├── button/ # 按钮组件
│ │ ├── src/ # 组件源码
│ │ │ └── button.vue
│ │ ├── style/ # 组件样式
│ │ │ └── index.scss
│ │ └── index.ts # 组件入口
│ ├── data-chart/ # 数据图表组件
│ ├── utils/ # 工具函数
│ ├── constants/ # 常量定义
│ └── index.ts # 总入口
├── dist/ # 构建产物
├── docs/ # 组件文档
└── package.json🧩 核心组件
基础组件
| 组件名 | 说明 | 文档 | |--------|------|------| | Button | 按钮组件 | 查看文档 | | Input | 输入框组件 | 查看文档 | | Select | 选择器组件 | 查看文档 |
数据展示
| 组件名 | 说明 | 文档 | |--------|------|------| | DataChart | 数据图表组件 | 查看文档 | | Table | 表格组件 | 查看文档 | | Card | 卡片组件 | 查看文档 |
导航组件
| 组件名 | 说明 | 文档 | |--------|------|------| | Menu | 菜单组件 | 查看文档 | | Breadcrumb | 面包屑组件 | 查看文档 | | Pagination | 分页组件 | 查看文档 |
反馈组件
| 组件名 | 说明 | 文档 | |--------|------|------| | Dialog | 对话框组件 | 查看文档 | | Message | 消息提示组件 | 查看文档 | | Loading | 加载组件 | 查看文档 |
🛠️ 开发指南
环境要求
- Node.js >= 16
- pnpm >= 7
- Vue >= 3.3
- TypeScript >= 4.9
本地开发
# 克隆项目
git clone <repository-url>
# 安装依赖
pnpm install
# 启动开发服务器
pnpm dev
# 构建组件库
pnpm build
# 运行测试
pnpm test创建新组件
创建组件目录
mkdir src/my-component cd src/my-component创建必要文件
my-component/ ├── src/ │ └── my-component.vue ├── style/ │ └── index.scss ├── index.ts └── README.md组件模板
<!-- src/my-component.vue --> <template> <div :class="ns.b()"> <slot /> </div> </template> <script setup lang="ts"> import { useNamespace } from '@qxs-bns/hooks' defineOptions({ name: 'QxsMyComponent' }) const ns = useNamespace('my-component') </script>样式文件
// style/index.scss @use 'sass:map'; @use '@qxs-bns/theme-chalk/src/mixins/mixins' as *; @use '@qxs-bns/theme-chalk/src/common/var' as *; @include b(my-component) { // 组件样式 }入口文件
// index.ts import { withInstall } from '@qxs-bns/utils' import MyComponent from './src/my-component.vue' export const QxsMyComponent = withInstall(MyComponent) export default QxsMyComponent export * from './src/my-component'
📋 开发规范
组件命名规范
Element Plus 二次封装组件
- 组件名:保持与 Element Plus 一致,添加
Qxs前缀 - 文件名:使用 kebab-case
- 样式类名:使用 Element Plus 的 BEM 命名规范
// ✅ 正确示例
export const QxsButton = withInstall(Button)
export const QxsInput = withInstall(Input)
// ❌ 错误示例
export const QxsBtn = withInstall(Button)
export const QxsInputField = withInstall(Input)自定义组件
- 组件名:使用
@qxs-bns/hooks中的useNamespace函数 - 文件名:使用 kebab-case
- 样式类名:使用 BEM 命名规范
<script setup lang="ts">
import { useNamespace } from '@qxs-bns/hooks'
defineOptions({
name: 'QxsDataChart' // 组件名使用 PascalCase
})
const ns = useNamespace('data-chart') // 使用 kebab-case
</script>
<template>
<div :class="ns.b()"> <!-- 生成 .qxs-data-chart -->
<div :class="ns.e('header')"> <!-- 生成 .qxs-data-chart__header -->
<div :class="ns.em('header', 'title')"> <!-- 生成 .qxs-data-chart__header--title -->Props 设计规范
// 使用 TypeScript 接口定义 Props
interface ButtonProps {
/**
* 按钮类型
* @default 'default'
*/
type?: 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'default'
/**
* 按钮尺寸
* @default 'default'
*/
size?: 'large' | 'default' | 'small'
/**
* 是否禁用
* @default false
*/
disabled?: boolean
/**
* 是否加载中
* @default false
*/
loading?: boolean
}
// 使用 withDefaults 设置默认值
const props = withDefaults(defineProps<ButtonProps>(), {
type: 'default',
size: 'default',
disabled: false,
loading: false
})事件设计规范
// 定义事件类型
interface ButtonEmits {
/**
* 点击事件
* @param event 原生事件对象
*/
click: [event: MouseEvent]
/**
* 焦点事件
* @param event 原生事件对象
*/
focus: [event: FocusEvent]
/**
* 失焦事件
* @param event 原生事件对象
*/
blur: [event: FocusEvent]
}
const emit = defineEmits<ButtonEmits>()
// 事件处理
const handleClick = (event: MouseEvent) => {
if (props.disabled || props.loading) return
emit('click', event)
}样式规范
SCSS 变量使用
// 使用主题变量
@use '@qxs-bns/theme-chalk/src/common/var' as *;
@include b(button) {
// 使用 CSS 变量
background-color: var(#{getCssVarName('button', 'bg-color')});
border-color: var(#{getCssVarName('button', 'border-color')});
color: var(#{getCssVarName('button', 'text-color')});
// 状态样式
@include when(disabled) {
opacity: var(#{getCssVarName('disabled-opacity')});
cursor: not-allowed;
}
// 修饰符样式
@include m(primary) {
background-color: var(#{getCssVarName('color-primary')});
border-color: var(#{getCssVarName('color-primary')});
}
}BEM 命名规范
// Block(块)
.qxs-button { }
// Element(元素)
.qxs-button__icon { }
.qxs-button__text { }
// Modifier(修饰符)
.qxs-button--primary { }
.qxs-button--large { }
// State(状态)
.qxs-button.is-disabled { }
.qxs-button.is-loading { }🧪 测试规范
单元测试
// button.test.ts
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import Button from '../src/button.vue'
describe('Button', () => {
it('should render correctly', () => {
const wrapper = mount(Button, {
props: { type: 'primary' },
slots: { default: 'Click me' }
})
expect(wrapper.classes()).toContain('qxs-button--primary')
expect(wrapper.text()).toBe('Click me')
})
it('should emit click event', async () => {
const wrapper = mount(Button)
await wrapper.trigger('click')
expect(wrapper.emitted('click')).toHaveLength(1)
})
it('should not emit click when disabled', async () => {
const wrapper = mount(Button, {
props: { disabled: true }
})
await wrapper.trigger('click')
expect(wrapper.emitted('click')).toBeUndefined()
})
})组件快照测试
// button.snap.test.ts
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import Button from '../src/button.vue'
describe('Button Snapshots', () => {
it('should match snapshot with different types', () => {
const types = ['primary', 'success', 'warning', 'danger', 'info']
types.forEach(type => {
const wrapper = mount(Button, {
props: { type },
slots: { default: 'Button' }
})
expect(wrapper.html()).toMatchSnapshot(`button-${type}`)
})
})
})📖 文档规范
组件文档模板
每个组件都应该包含完整的 README.md 文档:
# Button 按钮
常用的操作按钮。
## 基础用法
基础的按钮用法。
:::demo 使用 `type`、`plain`、`round` 和 `circle` 属性来定义 Button 的样式。
button/basic
:::
## API
### Button Attributes
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|--------|------|------|--------|--------|
| type | 类型 | string | primary / success / warning / danger / info / text | — |
| size | 尺寸 | string | large / small / mini | — |
| disabled | 是否禁用状态 | boolean | — | false |
### Button Events
| 事件名 | 说明 | 参数 |
|--------|------|------|
| click | 点击时触发 | (event: Event) |
### Button Slots
| 插槽名 | 说明 |
|--------|------|
| — | 默认插槽 |🤝 贡献指南
提交规范
使用 Conventional Commits 规范:
# 新功能
feat(button): add loading state support
# 修复 bug
fix(data-chart): resolve chart rendering issue
# 文档更新
docs(readme): update installation guide
# 样式调整
style(button): adjust padding and margin
# 重构代码
refactor(utils): optimize namespace function
# 性能优化
perf(table): improve virtual scrolling performance
# 测试相关
test(button): add unit tests for disabled state开发流程
- Fork 项目
- 创建功能分支
git checkout -b feat/new-component - 开发组件
- 编写组件代码
- 添加单元测试
- 编写文档
- 提交代码
git add . git commit -m "feat(new-component): add new component" - 推送分支
git push origin feat/new-component - 创建 Pull Request
代码审查清单
- [ ] 组件命名符合规范
- [ ] TypeScript 类型定义完整
- [ ] 单元测试覆盖率 > 80%
- [ ] 文档完整且示例可运行
- [ ] 样式符合设计规范
- [ ] 无障碍性支持
- [ ] 国际化支持
🔧 常见问题
Q: 如何自定义主题?
A: 通过 CSS 变量覆盖默认主题:
:root {
--qxs-color-primary: #409eff;
--qxs-color-success: #67c23a;
--qxs-color-warning: #e6a23c;
--qxs-color-danger: #f56c6c;
--qxs-color-info: #909399;
}Q: 如何按需引入组件?
A: 使用 ES6 模块语法:
import { QxsButton, QxsInput } from '@qxs-bns/components'Q: 如何贡献新组件?
A: 请参考 贡献指南 部分。
📄 许可证
MIT License - 详见 LICENSE 文件。
