first commit
This commit is contained in:
403
docs/多端适配方案.md
Normal file
403
docs/多端适配方案.md
Normal 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
|
||||
// 统一使用 rpx,UniApp 会自动转换
|
||||
.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'
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user