Files
dabai_web_f/docs/多端适配方案.md

404 lines
7.8 KiB
Markdown
Raw Permalink Normal View History

2026-03-17 14:52:07 +08:00
# 多端适配方案
## 一、平台差异处理
### 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'
})
}
})
```