- 🔥 完全重写 .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提供准确的移动端开发上下文,确保生成代码完全符合实际项目架构。
1032 lines
25 KiB
Markdown
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
|
|
|
|
### 后续计划
|
|
|
|
- 根据实际开发反馈持续优化规范
|
|
- 定期检查规范与实际代码的一致性
|
|
- 新增功能时同步更新规范文档
|
|
- 收集团队使用反馈并改进规范
|
|
|
|
---
|
|
|
|
**📌 重要提醒**: 本规范基于实际项目代码制定,所有示例代码均可直接使用。遵循本规范能够确保代码质量,提升开发效率,并为用户提供优秀的移动端体验。
|
|
|
|
**🎯 目标**: 为智慧校园移动端开发提供完整、准确、实用的规范指导,确保项目的可维护性和可扩展性。
|