# Mini UI包开发规范 ## 版本信息 | 版本 | 日期 | 描述 | 作者 | |------|------|------|------| | 1.1 | 2025-12-26 | 添加图标使用规范(Heroicons) | Bob (Scrum Master) | | 1.0 | 2025-12-26 | 基于史诗011和017经验创建Mini UI包开发规范 | Bob (Scrum Master) | ## 概述 本文档专门针对Taro小程序UI包(mini-ui-packages)的开发规范,基于史诗011(用人方小程序)和史诗017(人才小程序)的实施经验总结。Mini UI包与Web UI包有显著的差异,特别是在布局、组件行为和平台特性方面。 **适用范围:** - `mini-ui-packages/` 目录下的所有UI包 - 使用Taro框架的小程序项目 - 所有基于`@tarojs/components`的组件开发 ## Taro小程序核心布局规范 ### 1. View组件的默认布局行为 **重要**: 在Taro小程序中,`` 组件内的子元素默认是**横向布局**(`flex-row`),这与Web开发的div默认垂直布局行为完全不同。 #### 1.1 垂直布局规范 **问题**: View容器默认横向布局,导致子元素横向排列 **解决方案**: 必须显式添加 `flex flex-col` 类才能实现垂直布局 **正确示例**: ```typescript import { View, Text } from '@tarojs/components' // ✅ 正确: 使用 flex flex-col 实现垂直布局 姓名: 张三 性别: 男 年龄: 35 // ❌ 错误: 缺少 flex flex-col,子元素会横向排列 姓名: 张三 性别: 男 年龄: 35 ``` #### 1.2 信息卡片布局模式 **来源**: 史诗011.003经验总结 **标准模式**: ```typescript import { View, Text } from '@tarojs/components' export function PersonalBasicInfo({ personalInfo }: { personalInfo: PersonalInfoResponse }) { return ( 个人基本信息 {/* 垂直布局的信息列表 - 必须使用 flex flex-col */} 姓名 {personalInfo.name} 性别 {personalInfo.gender} 年龄 {personalInfo.age} {/* 更多字段... */} ) } ``` **关键点**: 1. **信息列表容器**必须使用 `flex flex-col` 实现垂直布局 2. **每个信息项**使用 `flex justify-between` 实现标签和值的左右分布 3. 使用 `space-y-2` 或 `space-y-3` 添加垂直间距 4. **重要**: 记住在所有需要垂直排列的 View 上添加 `flex flex-col` ### 2. Text组件的默认内联行为 **问题**: Text组件默认是内联显示(类似Web中的``),不会自动换行 **影响**: 导致多个Text组件在同一行显示,即使它们在不同的代码行上 **解决方案**: 使用`flex flex-col`强制Text组件垂直排列 **实际案例** (来源: 史诗011.003): ```typescript // ❌ 错误: Text组件会内联显示在同一行 统计1 统计2 统计3 // ✅ 正确: 使用 flex flex-col 强制垂直排列 统计1 统计2 统计3 ``` ### 3. 常见布局模式 #### 3.1 卡片容器布局 ```typescript 卡片标题 {/* 内容区域 - 垂直布局 */} {items.map(item => ( {item.label} {item.value} ))} ``` #### 3.2 列表项布局 ```typescript {list.map(item => ( {/* 列表项标题 */} {item.title} {/* 列表项内容 - 垂直布局 */} {item.description} {item.date} ))} ``` #### 3.3 网格布局 ```typescript {/* 2列网格 */} {items.map(item => ( {item.title} {item.value} ))} ``` ## 图标使用规范 ### 3.1 图标系统概述 **项目使用的图标库**: Heroicons (UnoCSS图标集) **图标类命名规范**: `i-heroicons-{icon-name}-{size}-{style}` **重要**: **不要使用emoji**,必须使用Heroicons图标类。 ### 3.2 图标类使用规范 #### 3.2.1 基础图标使用 **正确示例**: ```typescript import { View } from '@tarojs/components' // ✅ 正确: 使用Heroicons图标类 // ❌ 错误: 使用emoji 🔔 👤 ``` #### 3.2.2 图标类命名格式 **格式**: `i-heroicons-{图标名称}-{尺寸}-{样式}` **常用图标名称**: - `chevron-left` - 左箭头 - `chevron-right` - 右箭头 - `user` - 用户 - `bell` - 通知铃 - `document-text` - 文档 - `chart-bar` - 图表 - `building-office` - 建筑/企业 - `calendar` - 日历 - `phone` - 电话 - `lock-closed` - 锁 - `camera` - 相机 - `qr-code` - 二维码 - `device-phone-mobile` - 手机 - `arrow-right-on-rectangle` - 登出/外跳 - `arrow-left-on-rectangle` - 登入/内跳 - `exclamation-triangle` - 警告 - `exclamation-circle` - 提示 - `photo` - 图片 - `arrow-path` - 加载中 **尺寸选项**: - `20` - 20x20 (推荐用于小程序) - `24` - 24x24 **样式选项**: - `solid` - 实心图标(推荐) - `outline` - 轮廓图标 #### 3.2.3 图标尺寸和颜色 **尺寸类**: ```typescript // 16px // 20px // 24px // 32px // 使用Tailwind文本尺寸 // 使用Tailwind文本尺寸 ``` **颜色类**: ```typescript // 灰色 // 蓝色 // 绿色 // 红色 // 白色 // 黄色 // 紫色 ``` #### 3.2.4 常见使用场景 **导航栏返回按钮**: ```typescript ``` **功能入口图标**: ```typescript 个人信息 考勤记录 薪资查询 企业信息 ``` **状态指示器**: ```typescript // 加载中 // 成功/提示 // 警告 // 错误 // 信息 ``` **输入框图标**: ```typescript ``` **二维码按钮**: ```typescript 张三 ``` #### 3.2.5 动画效果 **旋转动画**: ```typescript ``` **脉冲动画**: ```typescript ``` ### 3.3 Navbar图标规范 **返回按钮图标**: ```typescript leftIcon = 'i-heroicons-chevron-left-20-solid' ``` **示例**: ```typescript Taro.navigateBack()} /> ``` ### 3.4 TabBar图标规范 **使用iconClass属性**(推荐): ```typescript const tabList = [ { title: '首页', iconClass: 'i-heroicons-home-20-solid', selectedIconClass: 'i-heroicons-home-20-solid', pagePath: '/pages/index/index' }, { title: '考勤', iconClass: 'i-heroicons-calendar-20-solid', selectedIconClass: 'i-heroicons-calendar-20-solid', pagePath: '/pages/attendance/index' } ] ``` ### 3.5 图标查找参考 **Heroicons官方图标库**: https://heroicons.com/ **使用UnoCSS图标集**: 项目使用UnoCSS的Heroicons图标集,所有图标名称遵循Heroicons命名规范。 **查找图标的方法**: 1. 访问 Heroicons 官网查找所需图标 2. 记录图标名称(如 `user`, `chevron-left`) 3. 使用格式: `i-heroicons-{图标名称}-20-solid` 4. 添加尺寸和颜色类 ### 3.6 常见错误避免 **错误示例**: ```typescript // ❌ 错误1: 使用emoji 🔔 通知 👤 // ❌ 错误2: 使用文本符号 ← 返回 // ❌ 错误3: 使用其他图标库 person // ❌ 错误4: 忘记添加尺寸类 {/* 没有尺寸,可能不显示 */} // ❌ 错误5: 图标类名拼写错误 {/* 缺少s */} {/* ✅ 正确 */} ``` **正确示例**: ```typescript // ✅ 正确1: 使用Heroicons图标类 // ✅ 正确2: 添加尺寸和颜色 // ✅ 正确3: 图标+文本组合 联系电话 ``` ## Taro组件使用规范 ### 4.1 基础组件导入 ```typescript import { View, Text, Image, Button, ScrollView } from '@tarojs/components' import Taro from '@tarojs/taro' ``` ### 4.2 Image组件规范 ```typescript ``` **mode模式说明**: - `aspectFill`: 保持纵横比缩放图片,确保图片填充整个容器(可能裁剪) - `aspectFit`: 保持纵横比缩放图片,确保图片完全显示(可能有空白) - `widthFix`: 宽度不变,高度自动变化,保持原图宽高比 ### 4.3 ScrollView组件规范 ```typescript {items.map(item => ( {item.content} ))} ``` ### 4.4 Button组件规范 **注意**: Taro的Button组件有默认样式,如需自定义样式建议使用View ```typescript // ✅ 推荐: 使用View实现自定义按钮 确定 // ⚠️ 谨慎使用: Taro Button组件有平台默认样式 ``` ## Navbar导航栏集成规范 ### 5.1 Navbar组件来源 ```typescript import { Navbar } from '@d8d/mini-shared-ui-components/components/navbar' ``` ### 5.2 页面层级划分 **TabBar页面(一级,无返回按钮)**: - 首页/个人主页 - 列表页 - 个人信息页 - 设置页 **非TabBar页面(二级,带返回按钮)**: - 详情页 - 编辑页 - 从其他页面跳转来的页面 ### 5.3 Navbar配置规范 **TabBar页面(无返回按钮)**: ```typescript {}} placeholder fixed /> ``` **非TabBar页面(带返回按钮)**: ```typescript import Taro from '@tarojs/taro' Taro.navigateBack()} placeholder fixed /> ``` ### 5.4 完整页面结构示例 ```typescript import { View, ScrollView } from '@tarojs/components' import { Navbar } from '@d8d/mini-shared-ui-components/components/navbar' export function MyPage() { return ( {/* Navbar导航栏 */} {}} placeholder fixed /> {/* 页面内容 */} {/* 页面内容 */} ) } ``` ## 照片预览功能实现 ### 6.1 使用Taro.previewImage ```typescript import Taro from '@tarojs/taro' import { View, Image, Text } from '@tarojs/components' interface DocumentPhotoItemProps { type: string url: string } export function DocumentPhotoItem({ type, url }: DocumentPhotoItemProps) { const handlePreview = () => { Taro.previewImage({ current: url, // 当前显示图片的http链接 urls: [url] // 需要预览的图片http链接列表 }) } return ( {type} ) } ``` **多图片预览**: ```typescript const handlePreview = (currentIndex: number) => { Taro.previewImage({ current: images[currentIndex].url, urls: images.map(img => img.url) }) } ``` ## 数据脱敏规范 ### 7.1 银行卡号脱敏 ```typescript /** * 脱敏银行卡号 * @param cardNumber 完整银行卡号 * @returns 脱敏后的银行卡号(如:**** **** **** 1234) */ export function maskCardNumber(cardNumber: string): string { if (!cardNumber || cardNumber.length < 4) { return '****' } const last4 = cardNumber.slice(-4) return `**** **** **** ${last4}` } // 使用示例 银行卡号 {maskCardNumber(bankCard.cardNumber)} ``` ### 7.2 身份证号脱敏 ```typescript /** * 脱敏身份证号 * @param idCard 完整身份证号 * @returns 脱敏后的身份证号(如:3301**********1234) */ export function maskIdCard(idCard: string): string { if (!idCard || idCard.length < 8) { return '********' } const prefix = idCard.slice(0, 4) const suffix = idCard.slice(-4) return `${prefix}**********${suffix}` } // 使用示例 身份证号 {maskIdCard(personalInfo.idCard)} ``` ### 7.3 手机号脱敏 ```typescript /** * 脱敏手机号 * @param phone 完整手机号 * @returns 脱敏后的手机号(如:138****5678) */ export function maskPhone(phone: string): string { if (!phone || phone.length < 7) { return '****' } return `${phone.slice(0, 3)}****${phone.slice(-4)}` } ``` ## Mini UI包结构规范 ### 8.1 标准目录结构 ```text mini-ui-packages// ├── src/ │ ├── pages/ # 页面组件 │ │ └── PageName/ │ │ ├── PageName.tsx │ │ └── index.ts │ ├── components/ # UI组件 │ │ ├── ComponentName.tsx │ │ └── index.ts │ ├── api/ # API客户端 │ │ ├── client.ts │ │ └── index.ts │ ├── utils/ # 工具函数 │ │ ├── helpers.ts │ │ └── index.ts │ └── index.ts # 主入口 ├── tests/ # 测试文件 │ ├── pages/ │ │ └── PageName/ │ │ └── PageName.test.tsx │ └── components/ │ └── ComponentName.test.tsx ├── package.json ├── jest.config.cjs # Jest配置 └── tsconfig.json ``` ### 8.2 package.json配置 ```json { "name": "@d8d/", "version": "1.0.0", "type": "module", "main": "src/index.ts", "types": "src/index.ts", "exports": { ".": { "types": "./src/index.ts", "import": "./src/index.ts" }, "./api": { "types": "./src/api/index.ts", "import": "./src/api/index.ts" }, "./pages//": { "types": "./src/pages//.tsx", "import": "./src/pages//.tsx" } }, "dependencies": { "@d8d/mini-shared-ui-components": "workspace:*", "@tarojs/components": "^4.1.4", "@tarojs/taro": "^4.1.4", "react": "^19.1.0" }, "devDependencies": { "@testing-library/react": "^16.3.0", "jest": "^30.2.0", "ts-jest": "^29.4.5" } } ``` ## 测试规范 ### 9.1 Jest配置 ```javascript module.exports = { preset: 'ts-jest', testEnvironment: 'jsdom', setupFilesAfterEnv: ['@d8d/mini-testing-utils/setup'], moduleNameMapper: { '^@tarojs/taro$': '@d8d/mini-testing-utils/testing/taro-api-mock.ts', '\\.(css|less|scss)$': '@d8d/mini-testing-utils/testing/style-mock.js' }, testMatch: [ '/tests/**/*.test.{ts,tsx}' ], transform: { '^.+\\.(ts|tsx)$': 'ts-jest' } } ``` ### 9.2 组件测试示例 ```typescript import { render, screen } from '@testing-library/react' import { View, Text } from '@tarojs/components' import { MyComponent } from '../MyComponent' describe('MyComponent', () => { it('渲染组件并验证垂直布局', () => { render() // 验证组件包含 flex flex-col 类 const container = screen.getByTestId('my-container') expect(container.className).toContain('flex flex-col') }) }) ``` ## 常见问题和解决方案 ### 10.1 布局问题 **问题**: 元素横向排列而不是垂直排列 - **原因**: View容器默认是flex-row - **解决**: 添加`flex flex-col`类 **问题**: Text组件在同一行显示 - **原因**: Text组件默认是内联显示 - **解决**: 父容器添加`flex flex-col`类 ### 10.2 样式问题 **问题**: Tailwind样式不生效 - **原因**: 类名冲突或拼写错误 - **解决**: 检查类名拼写,确保使用正确的Tailwind类名 **问题**: 样式在不同平台表现不一致 - **原因**: 不同小程序平台的样式引擎差异 - **解决**: 使用Taro提供的跨平台样式方案,避免使用平台特有样式 ### 10.3 API问题 **问题**: RPC客户端类型错误 - **原因**: API路径映射错误或类型推断不正确 - **解决**: 验证后端路由定义,使用RPC推断类型 ## 最佳实践 ### 11.1 组件开发 1. **始终使用flex flex-col实现垂直布局** 2. **为每个View添加语义化的className** 3. **使用data-testid属性便于测试** 4. **组件props使用TypeScript接口定义** 5. **使用相对路径导入包内模块** ### 11.2 性能优化 1. **使用Image组件的lazyLoad属性** 2. **列表数据使用虚拟滚动** 3. **避免不必要的重渲染** 4. **使用React.memo优化组件性能** ### 11.3 代码质量 1. **遵循项目编码标准** 2. **编写单元测试和集成测试** 3. **使用TypeScript严格模式** 4. **运行pnpm typecheck确保类型正确** 5. **使用ESLint进行代码检查** ## 参考实现 ### 12.1 用人方小程序UI包 - `mini-ui-packages/yongren-dashboard-ui` - `mini-ui-packages/yongren-order-management-ui` - `mini-ui-packages/yongren-talent-management-ui` ### 12.2 人才小程序UI包 - `mini-ui-packages/rencai-dashboard-ui` - `mini-ui-packages/rencai-personal-info-ui` - `mini-ui-packages/rencai-auth-ui` ### 12.3 共享组件 - `mini-ui-packages/mini-shared-ui-components` ## 版本历史 | 版本 | 日期 | 变更说明 | 作者 | |------|------|----------|------| | 1.0 | 2025-12-26 | 初始版本,基于史诗011和017经验总结 | Bob (Scrum Master) | --- **重要提醒**: 1. 本规范专门针对Taro小程序UI包开发,与Web UI包开发规范(`ui-package-standards.md`)不同 2. `flex flex-col`是Taro小程序中最常用的布局类,请务必牢记 3. 所有Mini UI包的开发都应遵循本规范