first commit

This commit is contained in:
2026-03-17 14:52:07 +08:00
parent a23b829323
commit ec25e6e617
104 changed files with 35840 additions and 0 deletions

151
docs/uView使用指南.md Normal file
View File

@@ -0,0 +1,151 @@
# uView-Plus 使用指南
## 已完成集成步骤
1. ✅ 安装依赖:`npm install uview-plus --save`
2. ✅ 在 `main.js` 中引入并注册
3. ✅ 创建 `src/uni.scss` 并引入 uView 主题变量
4. ✅ 在 `vite.config.js` 中配置 SCSS 预处理器
5. ✅ 在 `pages.json` 中配置 easycom 自动引入
## 配置说明
### uni.scss
```scss
/* uView-Plus 主题变量配置 */
@import 'uview-plus/theme.scss';
```
### vite.config.js
```javascript
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@/uni.scss"; @import "@/styles/variables.scss"; @import "@/styles/mixins.scss";',
api: 'modern-compiler',
silenceDeprecations: ['legacy-js-api', 'import']
}
}
}
```
### pages.json
```json
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-plus/components/u-$1/u-$1.vue"
}
}
```
## 常用组件示例
### 1. 按钮 (u-button)
```vue
<u-button type="primary" text="主要按钮"></u-button>
<u-button type="success" text="成功按钮"></u-button>
<u-button type="warning" text="警告按钮"></u-button>
```
### 2. 加载动画 (u-loading-icon)
```vue
<u-loading-icon mode="spinner"></u-loading-icon>
<u-loading-icon mode="circle"></u-loading-icon>
```
### 3. 弹窗 (u-popup)
```vue
<u-popup v-model:show="show" mode="bottom" :round="10">
<view class="content">弹窗内容</view>
</u-popup>
```
### 4. 输入框 (u-input)
```vue
<u-input v-model="value" placeholder="请输入内容"></u-input>
```
### 5. 表单 (u-form)
```vue
<u-form :model="form" ref="formRef">
<u-form-item label="姓名" prop="name">
<u-input v-model="form.name" placeholder="请输入姓名"></u-input>
</u-form-item>
</u-form>
```
### 6. Toast 提示
```javascript
// 在组件中使用
this.$u.toast('提示内容')
```
### 7. 日历 (u-calendar)
```vue
<u-calendar v-model:show="show" @confirm="confirm"></u-calendar>
```
### 8. 时间选择器 (u-datetime-picker)
```vue
<u-datetime-picker
v-model:show="show"
v-model="currentDate"
mode="datetime"
@confirm="confirm"
></u-datetime-picker>
```
## 可以优化的现有组件
### LoadingOverlay.vue
可以使用 `u-loading-icon` 替代自定义加载动画:
```vue
<template>
<u-overlay :show="visible">
<view class="loading-box">
<u-loading-icon mode="spinner" size="40" color="#ffffff"></u-loading-icon>
</view>
</u-overlay>
</template>
```
### BookingPopup.vue
可以使用 `u-popup` 替代自定义弹窗:
```vue
<u-popup
v-model:show="visible"
mode="bottom"
:round="16"
:closeable="true"
@close="handleClose"
>
<!-- 弹窗内容 -->
</u-popup>
```
可以使用 `u-form``u-form-item` 优化表单:
```vue
<u-form :model="formData" ref="formRef" :rules="rules">
<u-form-item label="姓名" prop="name" required>
<u-input v-model="formData.name" placeholder="请填写您的姓名"></u-input>
</u-form-item>
<u-form-item label="电话" prop="phone" required>
<u-input v-model="formData.phone" type="number" maxlength="11"></u-input>
</u-form-item>
</u-form>
```
可以使用 `u-calendar` 替代自定义日期选择器
## 文档链接
- 官方文档https://uview-plus.jiangruyi.com/
- 组件列表https://uview-plus.jiangruyi.com/components/intro.html
## 注意事项
1. uview-plus 是专为 Vue3 + uni-app 设计的组件库
2. 组件通过 easycom 自动引入,无需手动 import
3. 所有组件以 `u-` 开头
4. 支持主题定制和暗黑模式

403
docs/多端适配方案.md Normal file
View File

@@ -0,0 +1,403 @@
# 多端适配方案
## 一、平台差异处理
### 1.1 条件编译
使用 UniApp 的条件编译处理不同平台的差异:
```javascript
// #ifdef MP-WEIXIN
// 微信小程序特有代码
wx.login()
// #endif
// #ifdef H5
// H5特有代码
window.location.href = '/login'
// #endif
// #ifdef APP-PLUS
// App特有代码
plus.runtime.restart()
// #endif
```
### 1.2 平台判断工具
使用封装的平台判断工具:
```javascript
import { getPlatform, isMiniProgram, isH5, isApp } from '@/utils/platform'
if (isMiniProgram()) {
// 小程序端逻辑
} else if (isH5()) {
// H5端逻辑
} else if (isApp()) {
// App端逻辑
}
```
## 二、API 适配
### 2.1 统一 API 封装
对不同平台的 API 进行统一封装:
```javascript
// 跨端导航
export const navigateTo = (url, params = {}) => {
const query = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key])}`)
.join('&')
const fullUrl = query ? `${url}?${query}` : url
uni.navigateTo({ url: fullUrl })
}
// 跨端存储
export const setStorage = (key, value) => {
// #ifdef MP-WEIXIN
wx.setStorageSync(key, value)
// #endif
// #ifdef H5
localStorage.setItem(key, JSON.stringify(value))
// #endif
// #ifdef APP-PLUS
plus.storage.setItem(key, JSON.stringify(value))
// #endif
}
```
### 2.2 第三方登录适配
不同平台的第三方登录实现:
```javascript
// 微信登录
export const wechatLogin = () => {
return new Promise((resolve, reject) => {
// #ifdef MP-WEIXIN
wx.login({
success: (res) => {
resolve(res.code)
},
fail: reject
})
// #endif
// #ifdef H5
// H5微信授权登录
const appId = 'YOUR_APP_ID'
const redirectUri = encodeURIComponent(window.location.href)
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_userinfo#wechat_redirect`
// #endif
})
}
```
## 三、样式适配
### 3.1 尺寸单位适配
- **小程序端**:使用 `rpx`750rpx = 屏幕宽度)
- **H5端**:使用 `rem``vw`
- **App端**:使用 `rpx``upx`
```scss
// 统一使用 rpxUniApp 会自动转换
.container {
width: 750rpx;
padding: 30rpx;
font-size: 28rpx;
}
```
### 3.2 安全区域适配
处理刘海屏、底部安全区域:
```scss
.page {
// 顶部安全区域
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
// 底部安全区域
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
```
### 3.3 状态栏高度适配
```javascript
// 获取状态栏高度
const systemInfo = uni.getSystemInfoSync()
const statusBarHeight = systemInfo.statusBarHeight
// 在样式中使用
const navBarHeight = statusBarHeight + 44 // 44为导航栏高度
```
## 四、功能适配
### 4.1 分享功能
```javascript
// 小程序分享
// #ifdef MP-WEIXIN
onShareAppMessage() {
return {
title: '分享标题',
path: '/pages/index/index',
imageUrl: '/static/share.png'
}
}
// #endif
// H5分享
// #ifdef H5
const shareToWechat = () => {
// 调用微信 JS-SDK
wx.updateAppMessageShareData({
title: '分享标题',
desc: '分享描述',
link: window.location.href,
imgUrl: 'https://example.com/share.png'
})
}
// #endif
```
### 4.2 支付功能
```javascript
// 统一支付接口
export const pay = (orderInfo) => {
return new Promise((resolve, reject) => {
// #ifdef MP-WEIXIN
wx.requestPayment({
timeStamp: orderInfo.timeStamp,
nonceStr: orderInfo.nonceStr,
package: orderInfo.package,
signType: 'MD5',
paySign: orderInfo.paySign,
success: resolve,
fail: reject
})
// #endif
// #ifdef H5
// H5微信支付
WeixinJSBridge.invoke('getBrandWCPayRequest', orderInfo, (res) => {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
resolve(res)
} else {
reject(res)
}
})
// #endif
// #ifdef APP-PLUS
// App支付
plus.payment.request('wxpay', orderInfo, resolve, reject)
// #endif
})
}
```
### 4.3 定位功能
```javascript
// 获取位置
export const getLocation = () => {
return new Promise((resolve, reject) => {
uni.getLocation({
type: 'gcj02',
success: (res) => {
resolve({
latitude: res.latitude,
longitude: res.longitude
})
},
fail: (err) => {
// #ifdef H5
// H5使用浏览器定位API
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
resolve({
latitude: position.coords.latitude,
longitude: position.coords.longitude
})
},
reject
)
} else {
reject(new Error('浏览器不支持定位'))
}
// #endif
// #ifndef H5
reject(err)
// #endif
}
})
})
}
```
## 五、性能适配
### 5.1 小程序分包
```json
{
"pages": [
"pages/index/index",
"pages/user/index"
],
"subPackages": [
{
"root": "subPackages/order",
"pages": [
"list/index",
"detail/index"
]
},
{
"root": "subPackages/product",
"pages": [
"list/index",
"detail/index"
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["subPackages/order"]
}
}
}
```
### 5.2 图片懒加载
```vue
<template>
<!-- 小程序端使用 lazy-load -->
<image
:src="imageSrc"
lazy-load
mode="aspectFill"
/>
<!-- H5端使用 Intersection Observer -->
<img
v-lazy="imageSrc"
alt="图片"
/>
</template>
```
### 5.3 长列表优化
```vue
<template>
<!-- 使用虚拟列表 -->
<recycle-list :list="dataList">
<template v-slot="{ item }">
<view class="list-item">
{{ item.title }}
</view>
</template>
</recycle-list>
</template>
```
## 六、兼容性处理
### 6.1 API 兼容性检查
```javascript
// 检查API是否支持
if (uni.canIUse('getSystemInfoSync')) {
const systemInfo = uni.getSystemInfoSync()
}
// 版本号比较
const compareVersion = (v1, v2) => {
const arr1 = v1.split('.')
const arr2 = v2.split('.')
const len = Math.max(arr1.length, arr2.length)
for (let i = 0; i < len; i++) {
const num1 = parseInt(arr1[i] || 0)
const num2 = parseInt(arr2[i] || 0)
if (num1 > num2) return 1
if (num1 < num2) return -1
}
return 0
}
// 使用示例
const systemInfo = uni.getSystemInfoSync()
if (compareVersion(systemInfo.SDKVersion, '2.10.0') >= 0) {
// 支持新API
}
```
### 6.2 样式兼容性
```scss
// 使用 CSS 变量实现主题切换
:root {
--primary-color: #1890ff;
--text-color: #333;
}
.button {
background-color: var(--primary-color);
color: var(--text-color);
}
// 使用 autoprefixer 自动添加前缀
.flex-container {
display: flex;
// 自动添加 -webkit-flex
}
```
## 七、调试技巧
### 7.1 多端调试
- **微信小程序**:使用微信开发者工具
- **H5**:使用浏览器开发者工具
- **App**:使用 HBuilderX 真机调试
### 7.2 日志输出
```javascript
// 开发环境输出日志
if (process.env.NODE_ENV === 'development') {
console.log('调试信息:', data)
}
// 使用条件编译输出平台信息
// #ifdef MP-WEIXIN
console.log('当前平台:微信小程序')
// #endif
```
### 7.3 错误监控
```javascript
// 全局错误捕获
uni.onError((error) => {
console.error('全局错误:', error)
// 上报到错误监控平台
})
// 网络错误监控
uni.onNetworkStatusChange((res) => {
if (!res.isConnected) {
uni.showToast({
title: '网络已断开',
icon: 'none'
})
}
})
```

300
docs/开发规范.md Normal file
View File

@@ -0,0 +1,300 @@
# 开发规范文档
## 一、命名规范
### 1.1 文件命名
- **页面文件**:使用小写字母,多个单词用短横线连接,如 `user-profile.vue`
- **组件文件**:使用大驼峰命名,如 `UserCard.vue``LoadingView.vue`
- **工具类文件**:使用小写字母,多个单词用短横线连接,如 `request.js``storage.js`
- **常量文件**:使用小写字母,如 `constants.js``env.js`
### 1.2 变量命名
- **普通变量**:使用小驼峰命名,如 `userName``userInfo`
- **常量**:使用全大写字母,单词间用下划线连接,如 `API_BASE_URL``MAX_RETRY_COUNT`
- **私有变量**:以下划线开头,如 `_privateMethod`
- **布尔值**:以 `is``has``can` 等开头,如 `isLogin``hasPermission`
### 1.3 函数命名
- **普通函数**:使用小驼峰命名,动词开头,如 `getUserInfo``handleClick`
- **事件处理函数**:以 `handle``on` 开头,如 `handleSubmit``onLoad`
- **工具函数**:使用动词开头,如 `formatDate``validatePhone`
### 1.4 组件命名
- **全局组件**:使用大驼峰命名,至少两个单词,如 `LoadingView``EmptyView`
- **页面组件**:使用大驼峰命名,如 `LoginPage``UserProfile`
- **业务组件**:使用大驼峰命名,体现业务含义,如 `UserCard``OrderList`
## 二、代码注释规范
### 2.1 文件注释
每个文件开头必须包含文件说明注释:
```javascript
/**
* 用户相关接口
* @author 张三
* @date 2024-01-01
*/
```
### 2.2 函数注释
关键函数必须添加注释,说明功能、参数、返回值:
```javascript
/**
* 用户登录
* @param {object} data 登录数据
* @param {string} data.phone 手机号
* @param {string} data.password 密码
* @returns {Promise<object>} 登录结果
*/
export const login = (data) => {
return request.post('/auth/login', data)
}
```
### 2.3 复杂逻辑注释
对于复杂的业务逻辑,必须添加行内注释:
```javascript
// 检查Token是否过期
if (tokenExpireTime < Date.now()) {
// Token已过期刷新Token
await refreshToken()
}
```
### 2.4 TODO注释
待完成的功能使用 TODO 标记:
```javascript
// TODO: 添加图片压缩功能
// FIXME: 修复在iOS端的兼容性问题
```
## 三、代码风格规范
### 3.1 缩进与空格
- 使用 2 个空格缩进
- 运算符前后加空格
- 逗号后加空格
- 对象属性冒号后加空格
### 3.2 引号使用
- JavaScript 统一使用单引号
- HTML 属性统一使用双引号
### 3.3 分号使用
- 语句结尾不使用分号(根据 Prettier 配置)
### 3.4 代码长度
- 单行代码不超过 100 个字符
- 函数代码行数不超过 50 行
- 文件代码行数不超过 500 行
## 四、Vue 组件规范
### 4.1 组件结构顺序
```vue
<template>
<!-- 模板内容 -->
</template>
<script>
// 1. 导入
import { ref } from 'vue'
// 2. 组件定义
export default {
name: 'ComponentName',
components: {},
props: {},
emits: [],
setup() {
// 3. 响应式数据
// 4. 计算属性
// 5. 方法
// 6. 生命周期
// 7. 返回
}
}
</script>
<style lang="scss" scoped>
/* 样式内容 */
</style>
```
### 4.2 Props 定义
Props 必须定义类型、默认值和校验:
```javascript
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0,
validator: (value) => value >= 0
}
}
```
### 4.3 事件命名
- 使用短横线命名:`@update-value`
- 使用动词开头:`@click``@change``@submit`
## 五、Git 提交规范
### 5.1 提交信息格式
```
<type>(<scope>): <subject>
<body>
<footer>
```
### 5.2 Type 类型
- `feat`: 新功能
- `fix`: 修复 Bug
- `docs`: 文档更新
- `style`: 代码格式调整
- `refactor`: 重构代码
- `perf`: 性能优化
- `test`: 测试相关
- `chore`: 构建/工具链相关
### 5.3 提交示例
```
feat(login): 添加手机号验证码登录功能
- 实现验证码发送接口
- 添加验证码输入组件
- 完成登录逻辑
Closes #123
```
## 六、API 接口规范
### 6.1 接口文件组织
按业务模块划分接口文件:
```
api/
├── modules/
│ ├── auth.js # 认证相关
│ ├── user.js # 用户相关
│ └── order.js # 订单相关
└── index.js # 统一导出
```
### 6.2 接口命名
- 使用动词开头:`getUserInfo``updateUserInfo`
- RESTful 风格:`getList``getDetail``create``update``delete`
### 6.3 接口注释
每个接口必须添加注释说明:
```javascript
/**
* 获取用户信息
* @param {string} userId 用户ID
* @returns {Promise<object>} 用户信息
*/
export const getUserInfo = (userId) => {
return request.get(`/user/${userId}`)
}
```
## 七、样式规范
### 7.1 选择器命名
- 使用短横线命名:`.user-card``.login-form`
- 避免使用 ID 选择器
- 避免使用标签选择器
### 7.2 样式组织
```scss
.component-name {
// 1. 定位属性
position: relative;
// 2. 盒模型属性
display: flex;
width: 100%;
padding: 20rpx;
// 3. 文本属性
font-size: 28rpx;
color: #333;
// 4. 其他属性
background-color: #fff;
// 5. 嵌套选择器
.child-element {
// ...
}
}
```
### 7.3 单位使用
- 小程序端:使用 `rpx`
- H5 端:使用 `rem``vw`
- 固定尺寸:使用 `px`
## 八、性能优化规范
### 8.1 图片优化
- 使用合适的图片格式WebP、JPEG、PNG
- 压缩图片大小
- 使用图片懒加载
- 使用雪碧图合并小图标
### 8.2 代码优化
- 避免在循环中进行复杂计算
- 使用防抖和节流
- 合理使用计算属性和侦听器
- 及时清理定时器和事件监听
### 8.3 网络优化
- 合并接口请求
- 使用请求缓存
- 实现请求重试机制
- 避免重复请求
## 九、安全规范
### 9.1 数据安全
- 敏感信息加密存储
- Token 定期刷新
- 防止 XSS 攻击
- 防止 CSRF 攻击
### 9.2 权限控制
- 实现路由权限控制
- 实现接口权限控制
- 实现按钮级权限控制
## 十、测试规范
### 10.1 单元测试
- 工具函数必须编写单元测试
- 测试覆盖率不低于 80%
- 使用 Jest 测试框架
### 10.2 集成测试
- 关键业务流程必须编写集成测试
- 使用 uni-automator 进行自动化测试
### 10.3 测试命名
```javascript
describe('工具函数测试', () => {
test('应该正确验证手机号', () => {
expect(isPhone('13800138000')).toBe(true)
})
})
```

531
docs/性能优化清单.md Normal file
View File

@@ -0,0 +1,531 @@
# 性能优化清单
## 一、首屏加载优化
### 1.1 代码分割
```javascript
// 路由懒加载
const UserProfile = () => import('@/pages/user/profile')
// 组件懒加载
components: {
HeavyComponent: () => import('@/components/HeavyComponent.vue')
}
```
### 1.2 小程序分包加载
```json
{
"subPackages": [
{
"root": "subPackages/order",
"pages": ["list/index", "detail/index"]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["subPackages/order"]
}
}
}
```
### 1.3 资源预加载
```javascript
// 预加载关键资源
onLoad() {
// 预加载下一页数据
this.preloadNextPage()
// 预加载图片
uni.preloadImage({
src: '/static/images/banner.jpg'
})
}
```
### 1.4 骨架屏
```vue
<template>
<view v-if="loading" class="skeleton">
<view class="skeleton-avatar" />
<view class="skeleton-line" />
<view class="skeleton-line" />
</view>
<view v-else class="content">
<!-- 实际内容 -->
</view>
</template>
```
## 二、渲染性能优化
### 2.1 虚拟列表
对于长列表使用虚拟滚动:
```vue
<template>
<recycle-list
:list="dataList"
:item-height="100"
>
<template v-slot="{ item }">
<view class="list-item">
{{ item.title }}
</view>
</template>
</recycle-list>
</template>
```
### 2.2 图片懒加载
```vue
<template>
<!-- 小程序端 -->
<image
:src="imageSrc"
lazy-load
mode="aspectFill"
/>
<!-- H5端使用 Intersection Observer -->
<img
v-lazy="imageSrc"
@load="handleImageLoad"
/>
</template>
```
### 2.3 防抖与节流
```javascript
import { debounce, throttle } from '@/utils/performance'
export default {
methods: {
// 搜索输入防抖
handleSearch: debounce(function(keyword) {
this.search(keyword)
}, 300),
// 滚动事件节流
handleScroll: throttle(function(e) {
this.updateScrollPosition(e)
}, 100)
}
}
```
### 2.4 条件渲染优化
```vue
<template>
<!-- 使用 v-show 代替 v-if频繁切换 -->
<view v-show="isVisible">内容</view>
<!-- 使用 v-if 代替 v-show不常切换 -->
<view v-if="hasPermission">内容</view>
<!-- 使用 v-once 渲染静态内容 -->
<view v-once>{{ staticContent }}</view>
</template>
```
## 三、网络请求优化
### 3.1 请求合并
```javascript
// 合并多个接口请求
async loadPageData() {
const [bannerData, menuData, contentData] = await Promise.all([
api.getBanner(),
api.getMenu(),
api.getContent()
])
this.bannerList = bannerData
this.menuList = menuData
this.contentList = contentData
}
```
### 3.2 请求缓存
```javascript
class RequestCache {
constructor() {
this.cache = new Map()
this.cacheTime = 5 * 60 * 1000 // 5分钟
}
get(key) {
const item = this.cache.get(key)
if (!item) return null
if (Date.now() - item.timestamp > this.cacheTime) {
this.cache.delete(key)
return null
}
return item.data
}
set(key, data) {
this.cache.set(key, {
data,
timestamp: Date.now()
})
}
}
// 使用缓存
const cache = new RequestCache()
export const getUserInfo = async (userId) => {
const cacheKey = `user_${userId}`
const cached = cache.get(cacheKey)
if (cached) return cached
const data = await request.get(`/user/${userId}`)
cache.set(cacheKey, data)
return data
}
```
### 3.3 请求重试
```javascript
async function requestWithRetry(config, retryCount = 0) {
try {
return await request(config)
} catch (error) {
if (retryCount < 3) {
await new Promise(resolve => setTimeout(resolve, 1000))
return requestWithRetry(config, retryCount + 1)
}
throw error
}
}
```
### 3.4 请求取消
```javascript
class RequestManager {
constructor() {
this.pendingRequests = new Map()
}
addRequest(key, requestTask) {
// 取消之前的相同请求
if (this.pendingRequests.has(key)) {
this.pendingRequests.get(key).abort()
}
this.pendingRequests.set(key, requestTask)
}
removeRequest(key) {
this.pendingRequests.delete(key)
}
cancelAll() {
this.pendingRequests.forEach(task => task.abort())
this.pendingRequests.clear()
}
}
```
## 四、内存优化
### 4.1 及时清理
```javascript
export default {
data() {
return {
timer: null,
observer: null
}
},
beforeUnmount() {
// 清理定时器
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
// 清理观察器
if (this.observer) {
this.observer.disconnect()
this.observer = null
}
// 清理事件监听
uni.offNetworkStatusChange()
}
}
```
### 4.2 大数据处理
```javascript
// 分批处理大数据
function processBigData(data, batchSize = 100) {
const batches = []
for (let i = 0; i < data.length; i += batchSize) {
batches.push(data.slice(i, i + batchSize))
}
return batches.reduce((promise, batch) => {
return promise.then(() => {
return new Promise(resolve => {
setTimeout(() => {
processBatch(batch)
resolve()
}, 0)
})
})
}, Promise.resolve())
}
```
### 4.3 WeakMap 使用
```javascript
// 使用 WeakMap 避免内存泄漏
const cache = new WeakMap()
function cacheData(obj, data) {
cache.set(obj, data)
}
function getCachedData(obj) {
return cache.get(obj)
}
```
## 五、图片优化
### 5.1 图片压缩
```javascript
// 上传前压缩图片
function compressImage(filePath) {
return new Promise((resolve, reject) => {
uni.compressImage({
src: filePath,
quality: 80,
success: (res) => resolve(res.tempFilePath),
fail: reject
})
})
}
```
### 5.2 图片格式选择
- **照片**:使用 JPEG 格式
- **图标**:使用 PNG 或 SVG 格式
- **动画**:使用 GIF 或 WebP 格式
- **透明背景**:使用 PNG 格式
### 5.3 响应式图片
```vue
<template>
<image
:src="getImageUrl()"
mode="aspectFill"
/>
</template>
<script>
export default {
methods: {
getImageUrl() {
const systemInfo = uni.getSystemInfoSync()
const dpr = systemInfo.pixelRatio
// 根据设备像素比选择图片
if (dpr >= 3) {
return this.image + '@3x.jpg'
} else if (dpr >= 2) {
return this.image + '@2x.jpg'
}
return this.image + '.jpg'
}
}
}
</script>
```
### 5.4 图片预加载
```javascript
function preloadImages(urls) {
return Promise.all(
urls.map(url => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: url,
success: resolve,
fail: reject
})
})
})
)
}
```
## 六、小程序特定优化
### 6.1 setData 优化
```javascript
// 避免频繁 setData
let updateTimer = null
let pendingData = {}
function batchUpdate(data) {
Object.assign(pendingData, data)
if (updateTimer) return
updateTimer = setTimeout(() => {
this.setData(pendingData)
pendingData = {}
updateTimer = null
}, 16) // 约60fps
}
// 避免 setData 传递大数据
// 不好的做法
this.setData({
list: this.data.list.concat(newList)
})
// 好的做法
this.setData({
[`list[${this.data.list.length}]`]: newItem
})
```
### 6.2 自定义组件
```javascript
// 使用自定义组件代替模板
Component({
options: {
// 启用纯数据字段
pureDataPattern: /^_/,
// 启用多slot支持
multipleSlots: true
},
properties: {
title: String
},
data: {
_privateData: 'private' // 纯数据字段,不参与渲染
}
})
```
### 6.3 分包预下载
```json
{
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["subPackages/order"]
}
}
}
```
## 七、H5 特定优化
### 7.1 PWA 支持
```javascript
// 注册 Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
// sw.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/static/css/main.css',
'/static/js/main.js'
])
})
)
})
```
### 7.2 CDN 加速
```javascript
// 静态资源使用 CDN
const CDN_URL = 'https://cdn.example.com'
export const getStaticUrl = (path) => {
return `${CDN_URL}${path}`
}
```
### 7.3 Gzip 压缩
```javascript
// vite.config.js
import viteCompression from 'vite-plugin-compression'
export default {
plugins: [
viteCompression({
algorithm: 'gzip',
ext: '.gz'
})
]
}
```
## 八、性能监控
### 8.1 性能指标收集
```javascript
// 页面加载时间
const pageLoadTime = performance.timing.loadEventEnd - performance.timing.navigationStart
// 首屏渲染时间
const firstPaintTime = performance.getEntriesByType('paint')[0].startTime
// 接口请求时间
const apiTime = performance.getEntriesByType('resource')
.filter(item => item.initiatorType === 'xmlhttprequest')
```
### 8.2 性能上报
```javascript
function reportPerformance(data) {
// 上报到监控平台
uni.request({
url: 'https://monitor.example.com/report',
method: 'POST',
data: {
type: 'performance',
...data
}
})
}
```
## 九、优化检查清单
- [ ] 启用代码分割和懒加载
- [ ] 实现图片懒加载
- [ ] 使用虚拟列表处理长列表
- [ ] 添加请求缓存机制
- [ ] 实现请求重试机制
- [ ] 合并并发请求
- [ ] 压缩图片资源
- [ ] 使用 CDN 加速静态资源
- [ ] 启用 Gzip 压缩
- [ ] 小程序分包加载
- [ ] 优化 setData 调用
- [ ] 及时清理定时器和监听器
- [ ] 使用防抖和节流
- [ ] 添加骨架屏
- [ ] 实现性能监控