# Cursor Rules - 移动端开发规范 (Vue 2 + uniapp + uview-ui)
## 适用范围
- **项目目录**: `mobile/` (智慧校园移动应用)
- **开发语言**: JavaScript (Vue 2)
- **平台支持**: H5、小程序、APP、鸿蒙
- **UI 框架**: uView UI 2.0.38 (Vue 2 版本)
---
# 智慧校园移动端开发规范
## 1. 🎯 技术栈规范
### 核心技术
- **基础框架**: uni-app + Vue 2.6.14
- **UI 组件库**: uview-ui 2.0.38 (Vue 2 版本)
- **开发语言**: JavaScript (ES6+)
- **样式预处理**: Sass 1.90.0
- **构建工具**: Vue CLI 5.0.8
- **代码规范**: ESLint 5.0.8
### 版本信息
```json
{
"name": "mobile2",
"version": "0.1.0",
"dependencies": {
"@dcloudio/uni-app": "^2.0.2-4070520250711001",
"uview-ui": "2.0.38",
"vue": ">= 2.6.14 < 2.7",
"vue-class-component": "^6.3.2",
"vue-property-decorator": "^8.0.0",
"vuex": "^3.2.0"
},
"devDependencies": {
"sass": "^1.90.0",
"vue-template-compiler": ">= 2.6.14 < 2.7",
"typescript": "~4.5.5"
}
}
```
## 2. 📁 项目结构规范
### 目录结构
```
mobile/
├── src/ # 源码目录
│ ├── components/ # 通用组件
│ │ ├── Card.vue # 卡片组件
│ │ ├── ServiceItem.vue # 服务项组件
│ │ └── GridLayout.vue # 网格布局组件
│ ├── pages/ # 页面文件
│ │ ├── index/ # 首页
│ │ │ └── index.vue # 首页内容
│ │ ├── login/ # 登录页
│ │ │ └── index.vue # 登录页面
│ │ └── task/ # 工作流页面
│ │ ├── myDocument.vue # 我发起的
│ │ ├── allTaskWaiting.vue # 我的待办
│ │ ├── taskFinish.vue # 我的已办
│ │ └── taskCopyList.vue # 抄送我的
│ ├── utils/ # 工具类
│ │ ├── request.js # 网络请求工具
│ │ ├── user.js # 用户管理工具
│ │ ├── permission.js # 权限管理工具
│ │ └── router.js # 路由管理工具
│ ├── common/ # 公共模块
│ │ ├── request.js # API请求封装
│ │ ├── storage.js # 存储工具
│ │ └── crypto.js # 加密工具
│ ├── static/ # 静态资源
│ │ ├── fonts/ # 字体文件
│ │ │ └── iconfont.css # 自定义图标
│ │ └── images/ # 图片资源
│ ├── App.vue # 应用入口
│ ├── main.ts # 项目入口
│ ├── pages.json # 页面配置
│ ├── manifest.json # 应用配置
│ └── uni.scss # 全局样式
├── package.json # 项目配置
├── vue.config.js # Vue CLI配置
└── README.md # 项目说明
```
## 3. 🎨 页面开发规范
### 页面模板标准
```vue
{{ pageTitle }}
```
### 页面样式规范
#### 使用 CSS 变量系统
```scss
// 主题色彩变量
:root {
--primary-color: rgb(93, 135, 255);
--primary-light: rgba(93, 135, 255, 0.1);
--primary-dark: rgb(73, 115, 235);
--success-color: #52c41a;
--warning-color: #faad14;
--error-color: #ff4d4f;
--text-primary: #262626;
--text-secondary: #595959;
--text-disabled: #bfbfbf;
--border-color: #f0f0f0;
--background-color: #f8f9fa;
--white: #ffffff;
--shadow-light: 0 2px 8px rgba(0, 0, 0, 0.06);
--shadow-medium: 0 4px 16px rgba(0, 0, 0, 0.12);
--radius-small: 4px;
--radius-medium: 8px;
--radius-large: 12px;
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
--transition-fast: 0.2s ease;
--transition-medium: 0.3s ease;
--font-size-xs: 12px;
--font-size-sm: 14px;
--font-size-md: 16px;
--font-size-lg: 18px;
--font-size-xl: 20px;
}
```
## 4. 🧩 组件开发规范
### 自定义组件模板
```vue
```
### 组件命名规范
- **文件命名**: 使用 PascalCase (如: `Card.vue`, `ServiceItem.vue`)
- **组件名称**: 使用 PascalCase (如: `Card`, `ServiceItem`)
- **引用方式**: 支持驼峰和短横线 (如: `` 或 ``)
## 5. 🎨 图标使用规范
### 🚨 强制性图标使用规范
**⚠️ 重要说明**: 移动端项目使用 iconfont 图标系统,同时支持 uview-ui 的 u-icon 组件!
#### 📋 图标使用策略
1. **✅ 优先使用 iconfont 图标**
```vue
```
2. **✅ 支持 uview-ui 的 u-icon 组件**
```vue
```
3. **🔄 动态图标类名**
```vue
```
### 图标配置文件
**位置**: `mobile/src/static/fonts/iconfont.css`
```css
.iconfont {
display: inline-block;
width: 16px;
height: 16px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
/* 用户图标 */
.icon-user {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z'/%3E%3C/svg%3E");
}
/* 密码锁图标 */
.icon-lock {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM9 6c0-1.66 1.34-3 3-3s3 1.34 3 3v2H9V6z'/%3E%3C/svg%3E");
}
/* 更多图标... */
```
### 全局引入配置
**位置**: `mobile/src/main.ts`
```javascript
import Vue from 'vue'
import App from './App.vue'
import './uni.promisify.adaptor'
import uView from "uview-ui";
Vue.use(uView);
Vue.config.productionTip = false
const app = new (typeof App === 'function' ? App : Vue.extend(Object.assign({ mpType: 'app' }, App)))
app.$mount();
```
**位置**: `mobile/src/App.vue`
```vue
```
### 标准使用方法
#### 基础用法
```vue
```
## 6. 📱 移动端UI组件规范
### 列表操作按钮设计规范 (2025-01-03 新增)
#### 🎯 设计原则
移动端列表中的操作按钮统一采用**图标+文字垂直排列**的无边框设计,提升用户体验和界面美观度。
#### 📋 标准按钮模板
```vue
查看详细
编辑
历史记录
删除
```
#### 🎨 标准样式定义
```scss
/* 操作按钮容器 */
.card-actions {
display: flex;
justify-content: space-around;
padding: 20rpx;
border-top: 1px solid #f0f0f0;
gap: 16rpx;
}
/* 统一按钮样式 */
.action-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 16rpx 20rpx;
border-radius: 12rpx;
background-color: #f8f9fa;
min-width: 120rpx;
transition: all 0.3s ease;
/* 点击动画效果 */
&:active {
transform: scale(0.95);
opacity: 0.8;
}
}
/* 按钮文字样式 */
.btn-text {
font-size: 24rpx;
margin-top: 8rpx;
color: #303133;
font-weight: 500;
}
/* 主题色彩方案 */
.info-btn {
background-color: rgba(60, 156, 255, 0.1);
.btn-text { color: #3c9cff; }
}
.success-btn {
background-color: rgba(90, 199, 37, 0.1);
.btn-text { color: #5ac725; }
}
.warning-btn {
background-color: rgba(255, 153, 0, 0.1);
.btn-text { color: #ff9900; }
}
.error-btn {
background-color: rgba(245, 108, 108, 0.1);
.btn-text { color: #f56c6c; }
}
.primary-btn {
background-color: rgba(51, 102, 255, 0.1);
.btn-text { color: #3366ff; }
}
.default-btn {
background-color: rgba(144, 147, 153, 0.1);
.btn-text { color: #909399; }
}
#### 🎨 按钮背景色规范
**📱 移动端按钮背景色设计规范**
**背景色选项**:
- ✅ **完全透明**: `rgba(r, g, b, 0)` - 无背景色,纯文字按钮
- ✅ **半透明背景色**: `rgba(r, g, b, 0.1)` 到 `rgba(r, g, b, 0.3)` - 有背景色的按钮
- ✅ **实色背景**: `rgba(r, g, b, 1)` - 完全实色背景
**推荐使用场景**:
- **完全透明背景**: 适用于简洁设计,强调文字内容
- **半透明背景**: 适用于需要视觉层次的场景
- **实色背景**: 适用于重要操作按钮
**当前项目使用**:
```scss
.info-btn {
background-color: rgba(60, 156, 255, 0); // ✅ 完全透明
.btn-text { color: #3c9cff; }
}
.success-btn {
background-color: rgba(90, 199, 37, 0); // ✅ 完全透明
.btn-text { color: #5ac725; }
}
.warning-btn {
background-color: rgba(255, 153, 0, 0); // ✅ 完全透明
.btn-text { color: #ff9900; }
}
```
**设计原则**:
- 根据设计需求选择合适的背景色
- 确保按钮文字清晰可读
- 保持整体视觉一致性
- 符合项目设计风格
```
#### 🔧 图标选择规范
| 功能类型 | 推荐图标 | 颜色 | 样式类 | 使用场景 |
|---------|---------|------|--------|----------|
| 查看详细 | `eye` | #3c9cff | info-btn | 查看、预览、详情 |
| 编辑修改 | `edit-pen` | #5ac725 | success-btn | 编辑、修改、更新 |
| 历史记录 | `clock` | #ff9900 | warning-btn | 时间、历史、记录 |
| 删除操作 | `trash` | #f56c6c | error-btn | 删除、移除、清空 |
| 下载导出 | `download` | #3c9cff | info-btn | 下载、导出、保存 |
| 上传提交 | `upload` | #5ac725 | success-btn | 上传、提交、发送 |
| 审核通过 | `checkmark` | #5ac725 | success-btn | 通过、确认、同意 |
| 审核拒绝 | `close` | #f56c6c | error-btn | 拒绝、关闭、取消 |
| 详情信息 | `info-circle` | #3c9cff | info-btn | 信息、说明、帮助 |
| 设置配置 | `setting` | #909399 | default-btn | 设置、配置、管理 |
| 分享转发 | `share` | #3366ff | primary-btn | 分享、转发、推送 |
| 收藏点赞 | `heart` | #f56c6c | error-btn | 收藏、点赞、喜欢 |
#### 💡 使用指导
1. **✅ 强制使用场景**
- 所有移动端列表页面的操作按钮
- 卡片组件中的操作按钮
- 表格行操作按钮
2. **🎨 设计要求**
- 图标大小统一为16px
- 文字大小统一为24rpx(12px)
- 按钮最小宽度120rpx
- 圆角半径12rpx
3. **🔄 交互要求**
- 必须包含点击动画效果(:active伪类)
- 缩放比例0.95,透明度0.8
- 过渡动画时间0.3s
4. **📏 布局要求**
- 使用flex布局,space-around分布
- 按钮间距16rpx
- 容器内边距20rpx
- 顶部边框分割线
#### 🚨 注意事项
- **禁止使用传统边框按钮**: 移动端列表不再使用``组件
- **图标组件规范**: 统一使用``组件
- **颜色主题一致**: 严格按照表格中的颜色方案
- **响应式适配**: 确保在不同屏幕尺寸下正常显示
- **无障碍访问**: 文字描述清晰,图标语义明确
#### 📝 完整示例
```vue
{{ item.title }}
{{ item.description }}
查看详细
编辑
历史记录
```
## 7. 🌐 API 接口规范
### 网络请求工具 (common/request.js)
```javascript
// API请求配置
const baseURL =
process.env.NODE_ENV === 'development'
? 'http://localhost:8080'
: 'https://your-api-domain.com';
// 统一请求方法
export const request = (options) => {
return new Promise((resolve, reject) => {
uni.request({
url: baseURL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
Authorization: getToken(),
...options.header,
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(res);
}
},
fail: (error) => {
reject(error);
},
});
});
};
// 获取token
function getToken() {
try {
const token = uni.getStorageSync('token');
return token ? `Bearer ${token}` : '';
} catch (e) {
return '';
}
}
// API方法封装
export const api = {
// 用户登录
login: (data) =>
request({
url: '/auth/login',
method: 'POST',
data: {
tenantId: data.tenantId || '000000',
username: data.username,
password: data.password,
clientId: data.clientId || 'e5cd7e4891bf95d1d19206ce24a7b32e',
grantType: data.grantType || 'password',
},
header: {
isToken: false,
isEncrypt: true,
repeatSubmit: false,
},
}),
// 获取用户信息
getUserInfo: () =>
request({
url: '/system/user/getInfo',
method: 'GET',
}),
// 获取租户列表
getTenantList: (isToken = false) =>
request({
url: '/auth/tenant/list',
method: 'GET',
header: {
isToken: isToken,
},
}),
// 注销登录
logout: () =>
request({
url: '/auth/logout',
method: 'POST',
}),
};
```
### 用户信息缓存工具 (common/storage.js)
```javascript
// 用户信息缓存工具
export const userStorage = {
// 保存登录信息
saveLoginInfo: (loginResult, userInfo) => {
try {
// 保存token
uni.setStorageSync('access_token', loginResult.access_token);
// 保存用户信息
if (userInfo) {
uni.setStorageSync('userInfo', JSON.stringify(userInfo));
}
// 保存登录状态
uni.setStorageSync('isLoggedIn', true);
console.log('用户登录信息已保存');
} catch (e) {
console.error('保存登录信息失败:', e);
}
},
// 获取用户信息
getUserInfo: () => {
try {
const userInfo = uni.getStorageSync('userInfo');
return userInfo ? JSON.parse(userInfo) : null;
} catch (e) {
console.error('获取用户信息失败:', e);
return null;
}
},
// 获取token
getToken: () => {
try {
return uni.getStorageSync('access_token') || '';
} catch (e) {
return '';
}
},
// 检查登录状态
isLoggedIn: () => {
try {
const isLoggedIn = uni.getStorageSync('isLoggedIn');
const token = uni.getStorageSync('access_token');
return !!(isLoggedIn && token);
} catch (e) {
return false;
}
},
// 清除登录信息
clearLoginInfo: () => {
try {
uni.removeStorageSync('access_token');
uni.removeStorageSync('userInfo');
uni.removeStorageSync('isLoggedIn');
console.log('用户登录信息已清除');
} catch (e) {
console.error('清除登录信息失败:', e);
}
},
};
```
## 7. 🔐 登录状态管理规范
### 登录页面开发规范
#### 登录页面模板 (pages/login/index.vue)
```vue
登录
登录中...
© 2025 杭州第一技师学院 All Rights Reserved.
```
### 登录状态验证规范
#### 全局登录验证
每个需要登录的页面都必须在 `onLoad` 生命周期中检查登录状态:
```javascript
// 页面登录状态检查模板
export default {
onLoad() {
this.checkLoginStatus();
},
methods: {
checkLoginStatus() {
if (!userStorage.isLoggedIn()) {
uni.reLaunch({
url: '/pages/login/index',
});
return false;
}
return true;
},
loadUserInfo() {
const userInfo = userStorage.getUserInfo();
if (userInfo && userInfo.user) {
this.userInfo.name = userInfo.user.nickName || userInfo.user.userName || '用户';
// 根据需要设置其他用户信息
}
},
},
};
```
## 8. 📱 页面配置规范
### pages.json 配置
```json
{
"easycom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
},
"pages": [
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "杭州第一技师学院智慧校园",
"navigationStyle": "custom"
}
},
{
"path": "pages/task/myDocument",
"style": {
"navigationBarTitleText": "我发起的",
"navigationBarBackgroundColor": "#5d87ff",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/task/allTaskWaiting",
"style": {
"navigationBarTitleText": "我的待办",
"navigationBarBackgroundColor": "#5d87ff",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/task/taskFinish",
"style": {
"navigationBarTitleText": "我的已办",
"navigationBarBackgroundColor": "#5d87ff",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/task/taskCopyList",
"style": {
"navigationBarTitleText": "抄送我的",
"navigationBarBackgroundColor": "#5d87ff",
"navigationBarTextStyle": "white"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "智慧校园",
"navigationBarBackgroundColor": "#5d87ff",
"backgroundColor": "#F8F8F8"
}
}
```
### manifest.json 配置
```json
{
"name": "mobile2",
"appid": "",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
"app-plus": {
"modules": {},
"distribute": {
"android": {
"permissions": [
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
]
},
"ios": {},
"sdkConfigs": {}
},
"usingComponents": true
},
"quickapp": {},
"mp-weixin": {
"usingComponents": true,
"appid": "",
"setting": {
"urlCheck": true
}
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"mp-qq": {
"usingComponents": true
}
}
```
## 9. 🎭 用户体验规范
### 交互设计规范
#### 动画效果使用
```javascript
// utils/animations.js - 动画工具
export const animationUtils = {
// 淡入动画
fadeIn: (element) => {
element.style.animation = 'fadeIn 0.3s ease';
},
// 滑入动画
slideUp: (element) => {
element.style.animation = 'slideUp 0.3s ease';
},
// 缩放动画
scale: (element) => {
element.style.animation = 'scale 0.2s ease';
},
}
// 在页面中使用
methods: {
handleItemClick() {
// 触觉反馈
uni.vibrateShort();
// 视觉反馈
// 处理点击逻辑
}
}
```
#### 手势操作支持
```javascript
// utils/gestures.js - 手势识别
export const gestureManager = {
// 初始化手势
init: (element, callbacks) => {
let startX, startY, startTime;
element.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
startTime = Date.now();
});
element.addEventListener('touchend', (e) => {
const endX = e.changedTouches[0].clientX;
const endY = e.changedTouches[0].clientY;
const endTime = Date.now();
// 判断手势类型
const deltaX = endX - startX;
const deltaY = endY - startY;
const deltaTime = endTime - startTime;
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) {
if (deltaX > 0) {
callbacks.swipeRight && callbacks.swipeRight();
} else {
callbacks.swipeLeft && callbacks.swipeLeft();
}
}
});
},
};
```
### 无障碍访问规范
```javascript
// utils/accessibility.js - 无障碍访问工具
export const accessibilityUtils = {
// 设置焦点
setFocus: (element) => {
element.focus();
},
// 添加ARIA标签
addAriaLabel: (element, label) => {
element.setAttribute('aria-label', label);
},
// 键盘导航支持
enableKeyboardNavigation: (container) => {
container.addEventListener('keydown', (e) => {
switch (e.key) {
case 'Tab':
// Tab导航逻辑
break;
case 'Enter':
case ' ':
// 激活元素
e.target.click();
break;
case 'Escape':
// 取消操作
break;
}
});
},
};
```
## 10. 🚀 性能优化规范
### 代码优化
#### 组件懒加载
```javascript
// 页面中使用懒加载
export default {
components: {
// 懒加载组件
LazyComponent: () => import('@/components/LazyComponent.vue'),
},
};
```
#### 图片优化
```vue
```
### 网络优化
#### 请求缓存策略
```javascript
// 智能缓存策略
export const cacheStrategy = {
// 短期缓存 (5分钟)
short: 5 * 60,
// 中期缓存 (30分钟)
medium: 30 * 60,
// 长期缓存 (24小时)
long: 24 * 60 * 60,
};
// API调用示例
export const api = {
getUserInfo: () => {
const cacheKey = 'userInfo';
const cached = storage.get(cacheKey);
if (cached) {
return Promise.resolve(cached);
}
return request({
url: '/user/info',
}).then((data) => {
storage.set(cacheKey, data, cacheStrategy.medium);
return data;
});
},
};
```
## 11. 🛠️ 开发工具配置
### 配置文件管理规范
#### manifest.json 配置 (推荐)
**⚠️ 重要**: uni-app 项目中,开发服务器配置应统一在 `manifest.json` 的 `h5.devServer` 中:
```json
{
"h5": {
"devServer": {
"https": false,
"allowedHosts": "all",
"port": 8081,
"host": "0.0.0.0",
"proxy": {
"/api": {
"target": "http://localhost:8080",
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
}
}
},
"publicPath": "./",
"router": {
"mode": "hash"
},
"title": "智慧校园移动端"
}
}
```
#### Vue CLI 配置 (vue.config.js)
**🔧 仅用于构建优化**,避免与 `manifest.json` 产生配置冲突:
```javascript
module.exports = {
transpileDependencies: ['uview-ui'],
configureWebpack: {
resolve: {
alias: {
'@': require('path').resolve(__dirname, 'src'),
},
},
},
};
```
#### 配置优先级说明
**uni-app 配置优先级**:
- **H5平台**: `manifest.json` > `vue.config.js`
- **小程序平台**: 仅使用 `manifest.json`
- **App平台**: 仅使用 `manifest.json`
**最佳实践**:
✅ **统一配置**: 开发服务器配置统一在 `manifest.json` 中
✅ **构建工具**: `vue.config.js` 仅用于构建优化
✅ **避免冲突**: 不要在两个文件中重复配置同一项目
✅ **多端兼容**: 确保配置在所有平台都生效
### 开发命令规范
```bash
# 安装依赖
npm install
# H5开发
npm run dev:h5
# 微信小程序开发
npm run dev:mp-weixin
# App开发
npm run dev:app-plus
# 构建H5
npm run build:h5
# 构建微信小程序
npm run build:mp-weixin
# 构建App
npm run build:app-plus
```
## 12. ✅ 最佳实践总结
### 代码规范
1. **文件组织**: 按功能模块组织文件结构
2. **组件复用**: 提取通用组件,避免重复代码
3. **样式管理**: 使用 CSS 变量系统,便于主题切换
4. **性能优化**: 合理使用缓存和懒加载
5. **用户体验**: 添加加载状态、错误处理和无障碍支持
### 开发流程
1. **需求分析** → 确定页面结构和功能
2. **组件设计** → 拆分可复用组件
3. **页面开发** → 按模板编写页面代码
4. **样式调优** → 使用统一的设计规范
5. **功能测试** → 多平台测试确保兼容性
6. **性能优化** → 优化加载速度和用户体验
### 质量保证
1. **代码审查**: 确保代码符合规范
2. **功能测试**: 确保所有功能正常工作
3. **兼容性测试**: 确保多平台兼容
4. **性能测试**: 确保应用性能满足要求
5. **用户体验测试**: 确保交互流畅自然
---
## 🎯 总结
本规范基于实际的 Vue 2 + uniapp + uview-ui 项目制定,提供了完整的移动端开发流程。
**✨ 技术特色**:
- ✅ **Vue 2**: 稳定的响应式框架
- ✅ **uview-ui**: 成熟的 Vue 2 UI 组件库
- ✅ **现代 CSS**: 使用 CSS 变量的设计系统
- ✅ **无障碍访问**: 完整的无障碍访问支持
- ✅ **智能缓存**: 高效的数据缓存策略
- ✅ **用户体验**: 流畅的动画和手势支持
**🎨 设计理念**:
- 现代简约的视觉设计
- 一致的交互体验
- 响应式适配
- 无障碍友好
**📱 平台支持**:
- H5 (Web)
- 微信小程序
- 支付宝小程序
- iOS/Android App
- 鸿蒙 App
遵循本规范能够确保代码质量、提升开发效率,并为用户提供优秀的移动端体验。
## 13. 🔧 uView 2.0 组件使用规范
### uview-ui 图标组件规范(2025-01-03 更新)
- 移动端UI开发中,图标组件统一使用 (uview-ui 2.x 官方标准),同时支持iconfont自定义图标。
- 推荐通过 easycom 自动全局注册,无需手动 import。
- 标准用法示例:
```vue
```
- 图标名称请参考 uview-ui 官方文档:https://www.uviewui.com/components/icon.html
### uview-ui 选择器组件规范(2025-01-03 新增)
**⚠️ 重要:u-picker组件必须严格按照以下规范使用,否则会出现数据显示空白问题!**
#### 1. 组件属性规范
```vue
keyName="label"
v-model="indexArray"
:show="showPicker"
@confirm="onConfirm"
@close="showPicker = false"
>
range-key="label"
@change="onChange"
>
```
#### 2. 数据格式要求
```javascript
// ✅ 正确的数据格式
data() {
return {
// 对象数组数据
optionsArray: [
{ label: "选项1", value: "1" },
{ label: "选项2", value: "2" },
{ label: "选项3", value: "3" }
],
// 选中索引(必须是数组格式)
indexArray: [0],
// 控制显示
showPicker: false
}
}
// 在模板中使用时,columns必须包装成二维数组
:columns="[optionsArray]" // 注意中括号包装
```
#### 3. 事件处理规范
```javascript
// ✅ 正确的事件处理
onConfirm(e) {
console.log('picker选择结果:', e);
const index = e.value[0]; // uview2格式:e.value
const selectedItem = this.optionsArray[index];
this.form.fieldName = selectedItem.value;
this.indexArray = [index];
this.showPicker = false;
}
// ❌ 错误的事件处理
onConfirm(e) {
const index = e.detail.value[0]; // 错误:小程序原生格式
}
```
#### 4. 完整使用示例
```vue
{{ getSelectedLabel() || '请选择' }}
```
#### 5. 常见错误及解决
- **问题1**: picker弹出后数据区域空白
- **原因**: 使用了`:range`而非`:columns`,或数据格式不是二维数组
- **解决**: 改用`:columns="[dataArray]"`格式
- **问题2**: 事件处理获取不到正确数据
- **原因**: 使用了`e.detail.value`而非`e.value`
- **解决**: 改用`e.value[0]`获取索引
- **问题3**: 无法显示中文选项文本
- **原因**: 未指定`keyName`属性
- **解决**: 添加`keyName="label"`指定显示字段
- 详细文档参考:https://www.uviewui.com/components/picker.html
### uview-ui 弹窗组件规范(2025-01-03 新增)
- 移动端弹窗开发统一使用 (uview-ui 2.x 官方标准)
- 推荐通过 easycom 自动全局注册,无需手动 import。
- 标准用法示例:
```vue
```
- 常用属性:
- `v-model`: 控制弹窗显示/隐藏
- `mode`: 弹出方向(bottom、top、left、right、center)
- `height`: 弹窗高度(bottom/top模式)
- `width`: 弹窗宽度(left/right模式)
- `border-radius`: 圆角大小
- `closeable`: 是否显示关闭图标
- `mask-close`: 是否允许点击遮罩关闭
- 详细文档参考:https://www.uviewui.com/components/popup.html
---
**📝 维护**: 移动端开发规范文档
**🔄 更新**: 2025-01-03 (调整为Vue 2 + uview-ui技术栈,新增弹窗组件规范)
**📁 文件**: .cursor/cursorrules-mobile.md