Files
dabai_web_f/docs/多端适配方案.md
2026-03-17 14:52:07 +08:00

404 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 多端适配方案
## 一、平台差异处理
### 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'
})
}
})
```