wz-uniapp/docs/Task1.md

405 lines
12 KiB
Markdown
Raw 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.

# UniApp + H5混合开发微信小程序 技术实施方案UniApp端
你希望通过UniApp开发微信小程序以web-view嵌套H5承载核心业务展示同时由UniApp原生层负责登录、退出、支付等核心能力以下是UniApp端的详细技术实施方案明确需要开发的核心模块、功能和关键逻辑。
## 一、整体架构与职责边界
### 核心分工
| 模块/能力 | UniApp小程序端负责 | H5端负责 |
|----------------|---------------------------------------------|--------------------------------|
| 用户身份 | 微信登录、token管理、用户信息存储、退出登录逻辑 | 接收并使用用户信息,触发退出登录指令 |
| 支付 | 调起微信支付、支付结果处理、支付状态同步 | 发起支付请求、展示支付结果 |
| 页面容器 | 提供tabBar框架、web-view容器、页面跳转控制 | 承载table栏、业务内容展示、内部页面跳转 |
| 通信 | 接收H5消息、主动向H5推送数据、处理通信异常 | 向UniApp发送指令、接收UniApp数据、展示状态反馈 |
## 二、UniApp端核心开发内容
### 1. 项目基础配置
#### 1全局配置pages.json
配置tabBar、页面路由、web-view权限等核心配置
```json
{
"pages": [
// 登录页
"pages/login/login",
// tabBar主页面嵌套web-view
"pages/index/index",
// 其他tabBar页面如需
"pages/my/my"
],
"tabBar": {
"color": "#666666",
"selectedColor": "#007AFF",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-active.png"
},
{
"pagePath": "pages/my/my",
"text": "我的",
"iconPath": "static/tabbar/my.png",
"selectedIconPath": "static/tabbar/my-active.png"
}
]
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序定位"
}
},
"webview": {
"webviewParameter": {
"allowUniversalAccessFromFileURLs": true,
"allowFileAccess": true
}
}
}
```
#### 2微信小程序配置manifest.json
开启微信小程序相关权限配置AppID等
```json
{
"mp-weixin": {
"appid": "你的微信小程序AppID",
"setting": {
"urlCheck": false, // 允许访问非域名白名单的H5开发阶段正式需配置白名单
"es6": true,
"postcss": true
},
"usingComponents": true,
"permission": {
"scope.userInfo": {
"desc": "获取你的用户信息用于登录"
}
}
}
}
```
### 2. 核心页面开发
#### 1登录页pages/login/login.vue
负责微信授权登录、获取用户信息、token存储
```vue
<template>
<view class="login-container">
<button open-type="getUserProfile" @click="wxLogin" type="primary">微信快捷登录</button>
</view>
</template>
<script>
export default {
methods: {
async wxLogin() {
try {
// 1. 获取微信登录code
const loginRes = await uni.login({ provider: 'weixin' });
if (loginRes.code) {
// 2. 调用后端接口换取用户token和信息
const userRes = await uni.request({
url: '你的后端登录接口', // 如https://api.xxx.com/wx/login
method: 'POST',
data: {
code: loginRes.code,
appid: '你的小程序AppID'
}
});
if (userRes.data.code === 200) {
// 3. 存储用户信息和token全局可用
const { token, userInfo } = userRes.data.data;
uni.setStorageSync('wx_token', token);
uni.setStorageSync('user_info', userInfo);
// 4. 登录成功跳转到首页
uni.switchTab({ url: '/pages/index/index' });
uni.showToast({ title: '登录成功', icon: 'success' });
} else {
uni.showToast({ title: userRes.data.msg, icon: 'none' });
}
}
} catch (err) {
uni.showToast({ title: '登录失败,请重试', icon: 'none' });
console.error('登录异常:', err);
}
}
}
};
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
button {
width: 80%;
height: 80rpx;
font-size: 32rpx;
}
</style>
```
#### 2tabBar首页pages/index/index.vue
核心容器页嵌套web-view、处理与H5的通信
```vue
<template>
<view class="webview-container">
<!-- web-view组件嵌套H5页面绑定通信事件 -->
<web-view
:src="h5Url"
@message="handleH5Message"
id="main-webview"
></web-view>
</view>
</template>
<script>
export default {
data() {
return {
h5Url: '你的H5网页地址', // 如https://h5.xxx.com/home
userToken: '',
userInfo: {}
};
},
onShow() {
// 页面显示时校验登录态,无登录态则跳转登录页
this.checkLoginStatus();
// 拼接用户信息到H5链接初始化传参
this.initH5Url();
},
methods: {
// 1. 校验登录状态
checkLoginStatus() {
this.userToken = uni.getStorageSync('wx_token');
this.userInfo = uni.getStorageSync('user_info');
if (!this.userToken) {
uni.redirectTo({ url: '/pages/login/login' });
}
},
// 2. 初始化H5链接携带用户信息
initH5Url() {
if (this.userToken) {
// 拼接token、用户ID等关键信息到H5链接
this.h5Url = `${this.h5Url}?token=${this.userToken}&userId=${this.userInfo.id}&nickName=${encodeURIComponent(this.userInfo.nickName)}`;
}
},
// 3. 接收H5发送的消息核心通信逻辑
handleH5Message(e) {
// H5发送的消息格式建议{ type: '指令类型', data: '指令参数' }
const [message] = e.detail.data;
if (!message) return;
switch (message.type) {
// H5触发支付
case 'triggerPay':
this.handlePay(message.data);
break;
// H5触发退出登录
case 'triggerLogout':
this.handleLogout();
break;
// H5请求重新获取用户信息
case 'getUserInfo':
this.sendUserInfoToH5();
break;
default:
console.log('未知指令类型:', message.type);
}
},
// 4. 处理支付逻辑UniApp原生调起微信支付
async handlePay(payParams) {
try {
// 4.1 调用后端获取微信支付参数如prepay_id
const payRes = await uni.request({
url: '你的后端支付接口', // 如https://api.xxx.com/pay/create
method: 'POST',
data: {
token: this.userToken,
...payParams // H5传递的订单ID、金额等参数
}
});
if (payRes.data.code !== 200) {
uni.showToast({ title: payRes.data.msg, icon: 'none' });
// 通知H5支付失败
this.sendMsgToH5({ type: 'payFail', data: payRes.data.msg });
return;
}
// 4.2 调起微信支付
const wxPayParams = payRes.data.data;
uni.requestPayment({
timeStamp: wxPayParams.timeStamp,
nonceStr: wxPayParams.nonceStr,
package: wxPayParams.package,
signType: 'MD5',
paySign: wxPayParams.paySign,
// 支付成功回调
success: () => {
uni.showToast({ title: '支付成功', icon: 'success' });
this.sendMsgToH5({ type: 'paySuccess', data: '支付成功' });
},
// 支付失败/取消回调
fail: (err) => {
uni.showToast({ title: '支付失败', icon: 'none' });
this.sendMsgToH5({ type: 'payFail', data: err.errMsg });
}
});
} catch (err) {
console.error('支付异常:', err);
this.sendMsgToH5({ type: 'payFail', data: '支付接口异常' });
}
},
// 5. 处理退出登录
handleLogout() {
// 清除本地存储的登录态
uni.removeStorageSync('wx_token');
uni.removeStorageSync('user_info');
// 通知H5退出成功
this.sendMsgToH5({ type: 'logoutSuccess' });
// 跳转登录页
uni.redirectTo({ url: '/pages/login/login' });
},
// 6. 主动向H5发送消息
sendMsgToH5(msg) {
// 创建web-view上下文指定ID与页面中web-view的id一致
const webViewCtx = uni.createWebViewContext('main-webview');
// 发送消息H5需监听message事件接收
webViewCtx.postMessage({ data: msg });
},
// 7. 主动向H5推送用户信息
sendUserInfoToH5() {
this.sendMsgToH5({
type: 'userInfo',
data: {
token: this.userToken,
userId: this.userInfo.id,
nickName: this.userInfo.nickName,
avatarUrl: this.userInfo.avatarUrl
}
});
}
}
};
</script>
<style scoped>
.webview-container {
width: 100%;
height: 100vh;
}
</style>
```
#### 3“我的”页面pages/my/my.vue
可选,如需原生展示用户信息、退出按钮等:
```vue
<template>
<view class="my-container">
<view class="user-info">
<image :src="userInfo.avatarUrl" class="avatar"></image>
<text class="nickname">{{ userInfo.nickName }}</text>
</view>
<button @click="handleLogout" type="warn">退出登录</button>
</view>
</template>
<script>
export default {
data() {
return {
userInfo: {}
};
},
onShow() {
this.userInfo = uni.getStorageSync('user_info');
},
methods: {
handleLogout() {
uni.removeStorageSync('wx_token');
uni.removeStorageSync('user_info');
uni.redirectTo({ url: '/pages/login/login' });
}
}
};
</script>
<style scoped>
.my-container {
padding: 40rpx;
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 60rpx;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
margin-right: 30rpx;
}
.nickname {
font-size: 36rpx;
font-weight: bold;
}
button {
width: 100%;
height: 80rpx;
}
</style>
```
### 3. 全局工具类(可选)
封装通信、登录校验等通用方法,便于复用:
```js
// common/utils.js
/**
* 向H5发送消息
* @param {String} webViewId web-view的ID
* @param {Object} msg 消息内容
*/
export const sendMsgToH5 = (webViewId, msg) => {
const webViewCtx = uni.createWebViewContext(webViewId);
webViewCtx.postMessage({ data: msg });
};
/**
* 校验登录态
* @returns {Boolean} 是否已登录
*/
export const checkLogin = () => {
const token = uni.getStorageSync('wx_token');
if (!token) {
uni.redirectTo({ url: '/pages/login/login' });
return false;
}
return true;
};
```
### 4. 关键注意事项
1. **域名白名单配置**微信小程序后台需配置H5域名、后端接口域名的白名单否则无法访问
2. **通信格式统一**UniApp与H5的通信消息需约定固定格式如`{type: 'xxx', data: 'xxx'}`),避免解析异常;
3. **支付权限**:确保小程序已开通微信支付权限,后端支付接口需正确对接微信支付商户平台;
4. **登录态同步**H5页面刷新时需重新从UniApp获取登录态可通过URL参数或postMessage
5. **兼容性**web-view组件在微信小程序中部分JS API有限制需避免在H5中调用小程序专属API如支付、登录
## 总结
UniApp端核心开发内容可归纳为3个关键点
1. **基础层**配置tabBar、页面路由、微信小程序权限搭建整体框架
2. **核心能力层**开发登录页实现微信授权登录在web-view容器页处理与H5的通信封装支付、退出登录等核心逻辑
3. **保障层**:统一通信格式、配置域名白名单、处理登录态同步,确保混合开发模式稳定运行。