# 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 ``` ### 页面样式规范 #### 使用 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 ``` ## 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 ``` ### 登录状态验证规范 #### 全局登录验证 每个需要登录的页面都必须在 `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 ``` #### 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