Files
hzdyjs/docs/开发文档/移动端开发规范总结.md
T
zlwu 28232d5d46 feat: 移动端开发规范重大更新
- 🔥 完全重写 .cursor/cursorrules-mobile.md (940行)
  * 基于实际mobile工程Vue 3.4.21+uniapp+uview-plus架构
  * 移除所有JeeSite相关内容,精准匹配实际项目
  * 新增11个完整章节:技术栈、项目结构、页面开发、组件规范等

- 📚 创建完整规范文档 docs/开发文档/移动端开发规范总结.md (800+行)
  * 涵盖从项目架构到部署的全流程指导
  * 提供可直接使用的页面和组件模板
  * 包含现代CSS变量设计系统和用户体验优化

- 🔄 同步更新主配置文件 .cursorrules
  * 更新移动端技术栈描述
  * 调整为Vue 3.4.21+uniapp+uview-plus 3.4.45架构

- 📝 完善变更记录
  * 详细记录规范更新背景和技术价值
  * 为后续维护提供完整历史记录

核心价值:解决规范与实际项目不匹配问题,为Cursor AI提供准确的移动端开发上下文,确保生成代码完全符合实际项目架构。
2025-07-04 15:51:33 +08:00

1032 lines
25 KiB
Markdown

# 移动端开发规范总结文档
## 📋 文档概述
**文档目的**: 为智慧校园移动端开发提供完整的规范性指导文档
**适用项目**: `/mobile/` 目录下的 Vue 3 + uniapp + uview-plus 项目
**最后更新**: 2025-07-02 18:50:00
**维护人员**: wuzilong
---
## 🎯 项目技术架构总览
### 核心技术栈
```json
{
"基础框架": "uni-app + Vue 3.4.21",
"UI组件库": "uview-plus 3.4.45 (Vue 3版本)",
"开发语言": "JavaScript (ES6+)",
"国际化": "vue-i18n 9.1.9",
"样式预处理": "Sass 1.89.2",
"构建工具": "Vite 5.2.8",
"代码规范": "ESLint 9.30.1",
"状态管理": "无(纯净Vue 3架构)"
}
```
### 项目特色
- **🎨 现代化设计**: CSS 变量设计系统 + 响应式布局
- **♿ 无障碍访问**: 完整的 ARIA 支持和键盘导航
- **🎭 用户体验**: 动画效果、手势识别、触觉反馈
- **🚀 性能优化**: 智能缓存、组件懒加载、图片优化
- **📱 多端支持**: H5、微信小程序、App、鸿蒙全平台
---
## 📁 项目结构规范
### 标准目录结构
```
mobile/
├── src/ # 源码目录
│ ├── components/ # 通用组件
│ │ ├── NavBar.vue # 自定义导航栏
│ │ ├── Card.vue # 通用卡片组件
│ │ ├── ServiceItem.vue # 服务项组件
│ │ ├── StatCard.vue # 统计卡片组件
│ │ └── GridLayout.vue # 网格布局组件
│ ├── pages/ # 页面文件
│ │ ├── index/ # 首页 (底部导航)
│ │ ├── workbench/ # 办公中心 (底部导航)
│ │ └── profile/ # 我的页面 (底部导航)
│ ├── utils/ # 工具类库
│ │ ├── request.js # 网络请求工具
│ │ ├── sse.js # SSE实时数据
│ │ ├── device.js # 设备检测
│ │ ├── animations.js # 动画工具
│ │ ├── gestures.js # 手势识别
│ │ └── accessibility.js # 无障碍访问
│ ├── static/ # 静态资源
│ │ ├── tabbar/ # 底部导航图标
│ │ └── fonts/ # 字体文件
│ ├── App.vue # 应用入口
│ ├── main.js # 项目入口
│ ├── pages.json # 页面路由配置
│ ├── manifest.json # 应用配置
│ └── uni.scss # 全局样式变量
├── package.json # 项目配置
├── vite.config.js # Vite构建配置
├── eslint.config.cjs # ESLint配置
└── README.md # 项目说明
```
### 文件命名规范
- **页面文件**: `kebab-case` (如: `index.vue`)
- **组件文件**: `PascalCase` (如: `NavBar.vue`, `ServiceItem.vue`)
- **工具文件**: `camelCase` (如: `request.js`, `animations.js`)
- **静态资源**: `kebab-case` (如: `home-active.svg`)
---
## 🎨 页面开发规范
### 标准页面模板
```vue
<template>
<view class="page-container">
<!-- 自定义导航栏 -->
<NavBar
:title="pageTitle"
:show-refresh="true"
:show-search="true"
@refresh="handleRefresh"
@search="handleSearch"
/>
<!-- 主要内容区域 -->
<scroll-view class="main-content" scroll-y enhanced :show-scrollbar="false">
<!-- 页面内容 -->
<view class="content">
<!-- 使用uView-plus组件 -->
<u-cell-group>
<u-cell title="示例项目"></u-cell>
</u-cell-group>
</view>
<!-- 底部间距 -->
<view class="bottom-spacer"></view>
</scroll-view>
</view>
</template>
<script>
import NavBar from '@/components/NavBar.vue';
export default {
name: 'PageName',
components: {
NavBar,
},
data() {
return {
pageTitle: '页面标题',
// 页面数据
};
},
onLoad() {
// 页面加载逻辑
this.initPage();
},
onShow() {
// 页面显示逻辑
},
onUnload() {
// 页面卸载时清理定时器等
if (this.timer) {
clearInterval(this.timer);
}
},
methods: {
initPage() {
// 初始化页面逻辑
},
handleRefresh() {
// 刷新逻辑
uni.showLoading({ title: '刷新中...' });
setTimeout(() => {
uni.hideLoading();
uni.showToast({ title: '刷新成功', icon: 'success' });
}, 1000);
},
handleSearch() {
// 搜索逻辑
},
},
};
</script>
<style lang="scss" scoped>
.page-container {
min-height: 100vh;
background-color: var(--background-color);
display: flex;
flex-direction: column;
}
.main-content {
flex: 1;
padding-bottom: calc(50px + env(safe-area-inset-bottom));
}
.content {
padding: var(--spacing-md);
}
.bottom-spacer {
height: 20px;
}
</style>
```
### 页面开发要点
#### ✅ 必须遵循的规范
1. **导航栏配置**: 使用`navigationStyle: "custom"`,采用自定义 NavBar 组件
2. **安全区域适配**: 使用`env(safe-area-inset-bottom)`处理底部安全区域
3. **scroll-view 容器**: 使用`enhanced`属性提升滚动性能
4. **生命周期管理**: 正确使用`onLoad`、`onShow`、`onUnload`
5. **定时器清理**: 在`onUnload`中清理所有定时器和监听器
#### 🎨 样式规范
```scss
// 使用CSS变量系统
.page-container {
background-color: var(--background-color);
color: var(--text-primary);
}
// 使用工具类
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
// 使用统一间距
.mt-md {
margin-top: var(--spacing-md);
}
.p-lg {
padding: var(--spacing-lg);
}
```
---
## 🧩 组件开发规范
### 通用组件模板
```vue
<template>
<view class="component-wrapper" :class="computedClass">
<!-- 组件内容 -->
<slot></slot>
</view>
</template>
<script>
/**
* 智慧校园通用组件
* @property {String} customClass 自定义样式类
* @property {Boolean} disabled 是否禁用
* @example <custom-component :disabled="false">内容</custom-component>
*/
export default {
name: 'CustomComponent',
props: {
customClass: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
},
computed: {
computedClass() {
return {
disabled: this.disabled,
[this.customClass]: !!this.customClass,
};
},
},
methods: {
handleClick() {
if (this.disabled) return;
this.$emit('click');
// 触觉反馈
uni.vibrateShort();
},
},
};
</script>
<style lang="scss" scoped>
.component-wrapper {
transition: var(--transition-fast);
&.disabled {
opacity: 0.5;
pointer-events: none;
}
}
</style>
```
### 组件开发要点
#### ✅ 必须遵循的规范
1. **组件命名**: 使用 PascalCase,具有语义化的名称
2. **属性定义**: 提供完整的 props 配置,包含类型和默认值
3. **事件抛出**: 使用`$emit`向父组件传递事件
4. **样式作用域**: 使用`scoped`避免样式污染
5. **无障碍支持**: 添加适当的 ARIA 标签和键盘支持
6. **触觉反馈**: 在交互操作中添加`uni.vibrateShort()`
#### 🎯 组件分类
- **基础组件**: NavBar、Card、Button 等
- **业务组件**: ServiceItem、StatCard 等
- **布局组件**: GridLayout 等
- **工具组件**: Loading、Toast 等
---
## 🌐 API 接口规范
### 网络请求工具
```javascript
// utils/request.js
const baseURL =
process.env.NODE_ENV === 'development'
? 'http://localhost:3000/api'
: 'https://your-api-domain.com/api';
// 统一请求方法
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);
},
});
});
};
// API方法封装
export const api = {
// 用户登录
login: (data) => request({ url: '/auth/login', method: 'POST', data }),
// 获取用户信息
getUserInfo: () => request({ url: '/user/info' }),
// 获取首页数据
getHomeData: () => request({ url: '/home/data' }),
};
```
### 智能缓存策略
```javascript
// 缓存策略配置
export const cacheStrategy = {
short: 5 * 60, // 短期缓存 (5分钟)
medium: 30 * 60, // 中期缓存 (30分钟)
long: 24 * 60 * 60, // 长期缓存 (24小时)
};
// 数据缓存工具
export const storage = {
set: (key, value, expire) => {
try {
const data = {
value,
timestamp: Date.now(),
expire: expire ? Date.now() + expire * 1000 : null,
};
uni.setStorageSync(key, JSON.stringify(data));
} catch (e) {
console.error('缓存设置失败:', e);
}
},
get: (key) => {
try {
const data = uni.getStorageSync(key);
if (!data) return null;
const parsed = JSON.parse(data);
// 检查是否过期
if (parsed.expire && Date.now() > parsed.expire) {
uni.removeStorageSync(key);
return null;
}
return parsed.value;
} catch (e) {
console.error('缓存获取失败:', e);
return null;
}
},
};
```
### API 调用最佳实践
#### ✅ 推荐做法
```javascript
// 带缓存的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;
});
},
};
// 在页面中使用
methods: {
async loadUserInfo() {
try {
const userInfo = await api.getUserInfo();
this.userInfo = userInfo;
} catch (error) {
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
});
}
}
}
```
---
## 🎭 用户体验规范
### 动画效果规范
#### CSS 动画类
```scss
// 全局动画类 (uni.scss)
.fade-in {
animation: fadeIn var(--transition-medium);
}
.slide-up {
animation: slideUp var(--transition-medium);
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
```
#### JavaScript 动画工具
```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';
},
};
```
### 手势识别规范
```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 deltaX = endX - startX;
const deltaY = endY - startY;
// 判断手势类型
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;
}
});
},
};
```
---
## 📱 页面配置规范
### pages.json 标准配置
```json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页",
"navigationStyle": "custom"
}
},
{
"path": "pages/workbench/index",
"style": {
"navigationBarTitleText": "办公中心",
"navigationStyle": "custom"
}
},
{
"path": "pages/profile/index",
"style": {
"navigationBarTitleText": "我的",
"navigationStyle": "custom"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "智慧校园",
"navigationBarBackgroundColor": "rgb(93, 135, 255)",
"backgroundColor": "#f8f9fa"
},
"tabBar": {
"color": "#999999",
"selectedColor": "rgb(93, 135, 255)",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"height": "60px",
"fontSize": "12px",
"iconWidth": "22px",
"iconHeight": "22px",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/tabbar/home.svg",
"selectedIconPath": "static/tabbar/home-active.svg"
},
{
"pagePath": "pages/workbench/index",
"text": "办公中心",
"iconPath": "static/tabbar/workbench.svg",
"selectedIconPath": "static/tabbar/workbench-active.svg"
},
{
"pagePath": "pages/profile/index",
"text": "我的",
"iconPath": "static/tabbar/profile.svg",
"selectedIconPath": "static/tabbar/profile-active.svg"
}
]
}
}
```
### manifest.json 应用配置
```json
{
"name": "智慧校园",
"appid": "",
"description": "基于Vue3+uniapp的智慧校园移动应用",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
"vueVersion": "3",
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app",
"compilerVersion": 3,
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
},
"distribute": {
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>"
]
}
}
},
"mp-weixin": {
"appid": "",
"setting": {
"urlCheck": false
},
"usingComponents": true
},
"uniStatistics": {
"enable": false
}
}
```
---
## 🚀 性能优化规范
### 代码优化策略
#### 组件懒加载
```javascript
// 页面中使用懒加载组件
export default {
components: {
// 懒加载大型组件
HeavyComponent: () => import('@/components/HeavyComponent.vue'),
// 条件加载组件
ConditionalComponent: () => {
if (condition) {
return import('@/components/ConditionalComponent.vue');
}
return null;
},
},
};
```
#### 图片优化
```vue
<template>
<!-- 响应式图片 -->
<image
:src="imageSrc"
mode="aspectFit"
lazy-load
:fade-show="true"
@error="handleImageError"
@load="handleImageLoad"
/>
</template>
<script>
export default {
methods: {
handleImageError() {
console.log('图片加载失败');
// 可以设置默认图片
this.imageSrc = '/static/default-image.png';
},
handleImageLoad() {
console.log('图片加载成功');
},
},
};
</script>
```
#### 列表优化
```vue
<template>
<!-- 使用虚拟列表优化大数据 -->
<recycle-list class="recycle-list" :list-data="listData" :template-key="'type'">
<template v-slot:type1="{ item }">
<view class="list-item">{{ item.title }}</view>
</template>
</recycle-list>
</template>
```
### 网络优化策略
#### 请求优化
```javascript
// 请求防抖
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
// 在搜索中使用防抖
methods: {
handleSearch: debounce(function(keyword) {
this.searchData(keyword);
}, 300),
}
```
#### 缓存优化
```javascript
// 分级缓存策略
export const cacheManager = {
// 内存缓存(当前会话)
memoryCache: new Map(),
// 本地缓存(持久化)
setCache: (key, data, expire = cacheStrategy.medium) => {
// 内存缓存
cacheManager.memoryCache.set(key, data);
// 本地缓存
storage.set(key, data, expire);
},
getCache: (key) => {
// 优先从内存获取
if (cacheManager.memoryCache.has(key)) {
return cacheManager.memoryCache.get(key);
}
// 从本地存储获取
const data = storage.get(key);
if (data) {
// 回写内存缓存
cacheManager.memoryCache.set(key, data);
}
return data;
},
};
```
---
## 🛠️ 开发工具配置
### Vite 构建配置
```javascript
// vite.config.js
import { defineConfig } from 'vite';
import uni from '@dcloudio/vite-plugin-uni';
export default defineConfig({
plugins: [uni()],
server: {
port: 3000,
open: true,
host: '0.0.0.0',
},
build: {
// 生产环境优化
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
// 代码分割
rollupOptions: {
output: {
manualChunks: {
'uview-plus': ['uview-plus'],
vue: ['vue'],
},
},
},
},
// CSS优化
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@/uni.scss";',
},
},
},
});
```
### ESLint 代码规范
```javascript
// eslint.config.cjs
module.exports = [
{
files: ['src/**/*.{js,vue}'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
rules: {
// 代码风格
indent: ['error', 2],
quotes: ['error', 'single'],
semi: ['error', 'never'],
// Vue 3 规范
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
'vue/no-unused-components': 'error',
'vue/no-unused-vars': 'error',
// 性能相关
'no-console': 'warn',
'no-debugger': 'error',
'no-unused-vars': 'error',
},
},
];
```
---
## 📋 开发命令规范
### 标准开发命令
```bash
# 环境准备
npm install # 安装依赖
npm audit fix # 修复安全漏洞
# 开发调试
npm run dev:h5 # H5开发调试
npm run dev:mp-weixin # 微信小程序开发
npm run dev:app # App开发
# 生产构建
npm run build:h5 # H5生产构建
npm run build:mp-weixin # 微信小程序构建
npm run build:app # App构建
# 代码质量
npm run lint # 代码检查
npm run lint:fix # 自动修复代码问题
# 清理缓存
npm run clean # 清理构建缓存
```
### 发布流程
```bash
# 版本发布流程
npm run lint # 1. 代码检查
npm run build:h5 # 2. 构建H5版本
npm run build:mp-weixin # 3. 构建小程序版本
npm run build:app # 4. 构建App版本
```
---
## ✅ 最佳实践总结
### 🎯 核心开发原则
#### 1. 代码规范
- **文件组织**: 按功能模块清晰组织文件结构
- **组件复用**: 提取通用组件,避免重复代码
- **样式管理**: 使用 CSS 变量系统,便于主题切换
- **命名规范**: 采用语义化命名,提高代码可读性
#### 2. 性能优化
- **懒加载**: 合理使用组件和路由懒加载
- **缓存策略**: 实施分级缓存,提升响应速度
- **图片优化**: 使用响应式图片和懒加载
- **代码分割**: 合理分割代码包,减少初始加载
#### 3. 用户体验
- **加载状态**: 添加适当的加载提示
- **错误处理**: 友好的错误提示和降级方案
- **无障碍访问**: 完整的 ARIA 支持和键盘导航
- **触觉反馈**: 在交互操作中添加震动反馈
#### 4. 兼容性保证
- **多端测试**: 确保 H5、小程序、App 各端兼容
- **设备适配**: 支持各种屏幕尺寸和分辨率
- **版本兼容**: 考虑不同系统版本的兼容性
- **性能监控**: 监控各端性能表现
### 🔄 开发流程
```
1. 需求分析 → 确定页面结构和功能
2. 组件设计 → 拆分可复用组件
3. 页面开发 → 按模板编写页面代码
4. 样式调优 → 使用统一的设计规范
5. 功能测试 → 多平台测试确保兼容性
6. 性能优化 → 优化加载速度和用户体验
7. 代码审查 → 确保代码质量和规范性
8. 文档更新 → 同步更新相关文档
```
### 🎨 设计理念
- **现代简约**: 清新简洁的界面设计
- **一致性**: 统一的交互体验和视觉风格
- **响应式**: 适配多种屏幕尺寸和设备
- **无障碍**: 友好的无障碍访问支持
- **高性能**: 流畅的动画和快速的响应
---
## 📚 相关文档
### 技术文档
- **详细规范**: `.cursor/cursorrules-mobile.md`
- **项目说明**: `mobile/README.md`
- **API 接口**: `docs/开发文档/API/`
### 学习资源
- **Vue 3 官方文档**: https://cn.vuejs.org/
- **uni-app 官方文档**: https://uniapp.dcloud.net.cn/
- **uView Plus 文档**: https://uview-plus.jiangruyi.com/
### 工具支持
- **开发工具**: HBuilderX、VSCode
- **调试工具**: Vue DevTools、uni-app 调试工具
- **构建工具**: Vite、uni-cli
---
## 🔄 维护更新
### 更新日志
- **2025-07-02**: 初始版本,基于实际 mobile 工程代码编写
- **规范来源**: 深入分析 mobile 项目架构和代码实现
- **维护人员**: wuzilong
### 后续计划
- 根据实际开发反馈持续优化规范
- 定期检查规范与实际代码的一致性
- 新增功能时同步更新规范文档
- 收集团队使用反馈并改进规范
---
**📌 重要提醒**: 本规范基于实际项目代码制定,所有示例代码均可直接使用。遵循本规范能够确保代码质量,提升开发效率,并为用户提供优秀的移动端体验。
**🎯 目标**: 为智慧校园移动端开发提供完整、准确、实用的规范指导,确保项目的可维护性和可扩展性。