从零开始开发Uni-app+H5公众号全教程
本教程已完整覆盖Uni-app+H5公众号开发的核心流程与扩展功能
本教程将带领大家从零搭建Uni-app项目,适配H5端并集成微信公众号核心功能(如网页授权、JS-SDK调用、分享等),最终完成项目打包部署。全程配套实操步骤与代码示例,适合前端新手或需要快速落地公众号H5项目的开发者。
一、前置知识与环境准备
1.1 必备知识
-
基础HTML/CSS/JavaScript语法
-
Vue.js基础(Uni-app基于Vue语法,Vue3为主)
-
微信公众号基本概念(订阅号/服务号、AppID、网页授权等)
1.2 环境搭建
1.2.1 安装开发工具
Uni-app推荐使用HBuilderX开发,内置Uni-app编译环境,无需额外配置:
-
下载HBuilderX:https://www.dcloud.io/hbuilderx.html(选择「正式版」,根据系统选择Windows/Mac)
-
安装完成后,打开HBuilderX,进入「工具」-「插件安装」,搜索「Uni-app」插件并安装(默认已安装)
1.2.2 安装Node.js(可选)
若需要使用npm安装依赖(如微信JS-SDK),需安装Node.js:
-
下载Node.js:https://nodejs.org/zh-cn/(选择LTS长期支持版)
-
安装完成后,打开终端,输入
node -v和npm -v,若显示版本号则安装成功
1.2.3 微信公众号准备
需提前注册微信公众号(推荐服务号,订阅号部分接口权限受限),并完成基础配置:
-
注册/登录公众号:https://mp.weixin.qq.com/
-
获取AppID:登录后进入「设置与开发」-「基本配置」,记录「AppID(开发ID)」(后续项目配置需用到)
-
配置开发者工具:进入「设置与开发」-「开发者工具」-「web开发者工具」,绑定开发者微信号(用于本地调试)
二、创建Uni-app+H5项目
2.1 初始化Uni-app项目
-
打开HBuilderX,点击「文件」-「新建」-「项目」
-
选择「Uni-app」模板,输入项目名称(如「uniapp-wechat-h5」),选择「Vue3」,勾选「TypeScript」(可选,推荐),点击「创建」
-
项目目录说明(核心目录):
-
pages:存放页面文件(核心开发目录)
-
static:存放静态资源(图片、字体等)
-
main.ts:项目入口文件
-
pages.json:页面路由配置(Uni-app核心配置文件)
-
manifest.json:项目配置(如AppID、H5配置等)
-
2.2 配置H5端基础信息
打开项目根目录的「manifest.json」,进行H5端配置:
-
点击「H5配置」选项卡,填写「页面标题」(如「Uni-app公众号Demo」)
-
「运行基础路径」:本地开发时留空,部署时填写服务器访问路径(如「/uniapp-wechat/」)
-
「端口号」:默认8080,可自定义(避免端口占用)
-
「跨域设置」:点击「添加」,填写后端接口域名(如「https://api.example.com」),允许跨域请求
2.3 本地运行H5项目
-
右键项目根目录,选择「运行」-「运行到浏览器」-「选择浏览器(Chrome/Firefox等)」
-
等待编译完成,浏览器会自动打开项目(默认地址:http://localhost:8080),看到Uni-app默认首页则运行成功
三、公众号核心配置(网页授权+JS-SDK)
公众号H5开发的核心是集成微信网页授权(获取用户信息)和JS-SDK(调用微信原生功能,如分享、定位等),需先完成公众号后台配置与项目依赖引入。
3.1 公众号后台配置
3.1.1 配置网页授权域名
网页授权需指定域名(本地开发可使用内网穿透工具,如花生壳、natapp):
-
登录公众号后台,进入「设置与开发」-「公众号设置」-「功能设置」
-
找到「网页授权域名」,点击「设置」,输入需要授权的域名(如「example.com」,注意:无需http/https,且需备案)
-
下载校验文件,放置在服务器根目录(本地开发可跳过,内网穿透工具会自动处理),点击「保存」完成配置
3.1.2 配置JS接口安全域名
调用JS-SDK需配置安全域名:
-
进入「设置与开发」-「公众号设置」-「功能设置」,找到「JS接口安全域名」
-
点击「设置」,输入与网页授权一致的域名,下载校验文件并放置在服务器根目录,点击「保存」
3.2 项目集成微信JS-SDK
使用npm安装微信JS-SDK依赖(uni-app也可使用官方插件,此处推荐npm方式):
# 右键项目根目录,选择「在终端中打开」,输入以下命令
npm install weixin-js-sdk --save
3.3 封装微信授权与JS-SDK初始化工具
在项目根目录创建「utils/wechat.ts」文件,封装网页授权和JS-SDK初始化逻辑:
import wx from 'weixin-js-sdk';
import { getWechatConfig } from '@/api/wechat'; // 后续创建的后端接口请求
// 公众号AppID(从manifest.json或环境变量中获取)
const APPID = '你的公众号AppID';
/**
* 微信网页授权(获取code,用于后端换取openid)
* @param redirectUri 授权成功后跳转的页面路径(需编码)
*/
export const wechatAuth = (redirectUri: string = window.location.href) => {
const encodedRedirectUri = encodeURIComponent(redirectUri);
// 构造授权链接
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APPID}&redirect_uri=${encodedRedirectUri}&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect`;
// 跳转到授权页面
window.location.href = authUrl;
};
/**
* JS-SDK初始化
* @param url 当前页面URL(需与公众号安全域名一致)
*/
export const initWechatSdk = async (url: string = window.location.href) => {
try {
// 调用后端接口获取JS-SDK配置参数(timestamp、noncestr、signature等)
const res = await getWechatConfig({ url });
const { appId, timestamp, nonceStr, signature } = res.data;
// 初始化JS-SDK
wx.config({
debug: false, // 开发阶段可设为true,查看调试信息
appId,
timestamp,
nonceStr,
signature,
jsApiList: [
'updateAppMessageShareData', // 自定义分享给朋友
'updateTimelineShareData', // 自定义分享到朋友圈
'getLocation', // 获取地理位置
'scanQRCode', // 扫码
'chooseImage', // 拍照/选图
'uploadImage', // 上传图片到微信服务器
'chooseWXPay', // 微信支付
'requestSubscribeMessage' // 订阅消息授权
] // 需要调用的JS接口列表
});
// 初始化成功回调
wx.ready(() => {
console.log('JS-SDK初始化成功');
});
// 初始化失败回调
wx.error((err: any) => {
console.error('JS-SDK初始化失败:', err);
});
} catch (error) {
console.error('获取JS-SDK配置失败:', error);
}
};
/**
* 自定义分享配置
* @param title 分享标题
* @param desc 分享描述
* @param link 分享链接
* @param imgUrl 分享图标
*/
export const setWechatShare = (title: string, desc: string, link: string, imgUrl: string) => {
wx.ready(() => {
// 分享给朋友
wx.updateAppMessageShareData({
title,
desc,
link,
imgUrl,
success: () => {
console.log('分享给朋友配置成功');
}
});
// 分享到朋友圈
wx.updateTimelineShareData({
title,
link,
imgUrl,
success: () => {
console.log('分享到朋友圈配置成功');
}
});
});
};
/**
* 获取用户地理位置
* @param type 坐标类型(wgs84:GPS坐标,gcj02:火星坐标)
*/
export const getWechatLocation = () => {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.getLocation({
type: 'gcj02',
success: (res) => {
const { latitude, longitude } = res; // 纬度、经度
resolve({ latitude, longitude });
},
fail: (err) => {
console.error('获取地理位置失败:', err);
uni.showToast({ title: '获取位置失败,请允许定位权限', icon: 'none' });
reject(err);
}
});
});
});
};
/**
* 拍照/选图并上传到微信服务器
* @param count 最多选择图片数量
*/
export const chooseAndUploadImage = (count: number = 1) => {
return new Promise((resolve, reject) => {
wx.ready(() => {
// 1. 选择图片(拍照/从相册选)
wx.chooseImage({
count,
sizeType: ['original', 'compressed'], // 原图/压缩图
sourceType: ['album', 'camera'], // 相册/相机
success: (chooseRes) => {
const localIds = chooseRes.localIds; // 本地图片ID列表
// 2. 上传图片到微信服务器
wx.uploadImage({
localId: localIds[0], // 上传第一张图片(可循环上传多张)
isShowProgressTips: 1, // 显示进度提示
success: (uploadRes) => {
const serverId = uploadRes.serverId; // 微信服务器返回的图片ID(需传给后端下载)
resolve({ localId: localIds[0], serverId });
},
fail: (err) => {
console.error('图片上传失败:', err);
reject(err);
}
});
},
fail: (err) => {
console.error('选择图片失败:', err);
reject(err);
}
});
});
});
};
/**
* 检测微信版本是否满足要求
* @param requiredVersion 要求的版本(如'7.0.0')
* @returns 是否满足
*/
export const checkWechatVersion = (requiredVersion: string) => {
const wechatVersion = navigator.userAgent.match(/MicroMessenger\/(\d+\.\d+\.\d+)/)?.[1] || '';
if (!wechatVersion) return false;
const versionArr = wechatVersion.split('.').map(Number);
const requiredArr = requiredVersion.split('.').map(Number);
for (let i = 0; i < versionArr.length; i++) {
if (versionArr[i] > requiredArr[i]) return true;
if (versionArr[i] < requiredArr[i]) return false;
}
return true;
};
3.4 创建后端接口请求(api/wechat.ts)
封装获取JS-SDK配置参数的接口请求(需后端配合实现签名生成逻辑):
import request from '@/utils/request';
/**
* 获取微信JS-SDK配置参数
* @param params { url: string } 当前页面URL
*/
export const getWechatConfig = (params: { url: string }) => {
return request({
url: '/api/wechat/config', // 后端接口地址
method: 'get',
params
});
};
/**
* 用code换取用户信息(openid、昵称等)
* @param params { code: string } 网页授权获取的code
*/
export const getUserInfoByCode = (params: { code: string }) => {
return request({
url: '/api/wechat/userInfo',
method: 'get',
params
});
};
/**
* 创建订单并获取支付参数
* @param data { orderId: string, totalFee: number } 订单ID、订单金额(分)
*/
export const createOrderAndGetPayParams = (data: { orderId: string, totalFee: number }) => {
return request({
url: '/api/wechat/pay/createOrder',
method: 'post',
data
});
};
/**
* 查询支付结果
* @param params { orderId: string } 订单ID
*/
export const queryPayResult = (params: { orderId: string }) => {
return request({
url: '/api/wechat/pay/queryResult',
method: 'get',
params
});
};
/**
* 发送订阅消息
* @param data { templateId: string, page: string, data: any } 模板ID、跳转页面、模板数据
*/
export const sendSubscribeMessage = (data: {
templateId: string,
page: string,
data: Record<string, { value: string }>
}) => {
return request({
url: '/api/wechat/subscribe/send',
method: 'post',
data
});
};
3.5 封装请求工具(utils/request.ts)
基于uni.request封装全局请求工具,处理请求拦截、响应拦截:
import { showToast } from 'uni-app';
// 创建请求实例
const request = (options: any) => {
return new Promise((resolve, reject) => {
uni.request({
url: options.url,
method: options.method || 'GET',
data: options.data || {},
params: options.params || {},
header: {
'Content-Type': 'application/json',
...options.header
},
success: (res) => {
// 响应状态码判断
if (res.statusCode === 200) {
resolve(res.data);
} else {
showToast({
title: res.data.message || '请求失败',
icon: 'none'
});
reject(res.data);
}
},
fail: (err) => {
showToast({
title: '网络错误',
icon: 'none'
});
reject(err);
}
});
});
};
export default request;
四、核心功能开发实战
本节将实现3个核心功能:首页(触发微信授权+分享配置)、用户中心(展示用户信息)、扫码功能页,配套完整代码示例。
4.1 配置页面路由(pages.json)
修改pages.json,添加首页、用户中心、扫码页的路由配置:
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/user/user",
"style": {
"navigationBarTitleText": "用户中心"
}
},
{
"path": "pages/scan/scan",
"style": {
"navigationBarTitleText": "扫码功能"
}
},
{
"path": "pages/extend/extend",
"style": {
"navigationBarTitleText": "更多功能演示"
}
},
{
"path": "pages/pay/pay",
"style": {
"navigationBarTitleText": "确认支付"
}
},
{
"path": "pages/order/detail",
"style": {
"navigationBarTitleText": "订单详情"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "Uni-app公众号Demo",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
}
}
4.2 首页开发(pages/index/index.vue)
实现功能:页面加载时触发微信授权,获取用户信息后存储到本地,配置微信分享,添加跳转按钮:
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { wechatAuth, initWechatSdk, setWechatShare, checkWechatVersion } from '@/utils/wechat';
import { getUserInfoByCode } from '@/api/wechat';
import { useRouter } from 'uni-app';
const router = useRouter();
const userInfo = ref<any>(null);
onMounted(() => {
// 检测微信版本
if (!checkWechatVersion('7.0.0')) {
uni.showToast({ title: '微信版本过低,请升级后使用', icon: 'none' });
}
// 1. 初始化JS-SDK
initWechatSdk();
// 2. 配置微信分享
const shareConfig = {
title: 'Uni-app公众号Demo',
desc: '从零开始开发的Uni-app+H5公众号项目',
link: window.location.href,
imgUrl: 'https://example.com/logo.png' // 分享图标(需放在安全域名下)
};
setWechatShare(shareConfig.title, shareConfig.desc, shareConfig.link, shareConfig.imgUrl);
// 3. 处理微信授权回调(获取code)
handleAuthCallback();
});
/**
* 处理微信授权回调,获取code并换取用户信息
*/
const handleAuthCallback = () => {
// 从URL中解析code(微信授权成功后会将code拼接到redirectUri后)
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const localUserInfo = uni.getStorageSync('userInfo');
if (localUserInfo) {
// 本地已存储用户信息,直接读取
userInfo.value = localUserInfo;
} else if (code) {
// 有code,调用接口换取用户信息
getUserInfoByCode({ code }).then(res => {
userInfo.value = res.data;
// 存储用户信息到本地
uni.setStorageSync('userInfo', res.data);
});
} else {
// 无code,触发微信授权
wechatAuth();
}
};
/**
* 跳转用户中心
*/
const toUserPage = () => {
router.push('/pages/user/user');
};
/**
* 跳转扫码页
*/
const toScanPage = () => {
router.push('/pages/scan/scan');
};
/**
* 跳转更多功能演示页
*/
const toExtendPage = () => {
router.push('/pages/extend/extend');
};
/**
* 跳转支付测试页
*/
const toPayPage = () => {
// 模拟订单参数
router.push({
path: '/pages/pay/pay',
query: {
orderId: 'TEST' + Date.now(),
totalFee: 1 // 1分
}
});
};
</script>
4.3 用户中心开发(pages/user/user.vue)
实现功能:展示本地存储的用户信息,添加退出登录按钮:
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useRouter } from 'uni-app';
const router = useRouter();
const userInfo = ref<any>(null);
onMounted(() => {
// 读取本地存储的用户信息
const localUserInfo = uni.getStorageSync('userInfo');
if (localUserInfo) {
userInfo.value = localUserInfo;
} else {
// 无用户信息,跳转首页触发授权
router.push('/pages/index/index');
}
});
/**
* 退出登录:清除本地存储,跳转首页
*/
const logout = () => {
uni.removeStorageSync('userInfo');
router.push('/pages/index/index');
};
</script>
4.4 扫码功能开发(pages/scan/scan.vue)
实现功能:调用微信JS-SDK的扫码接口,展示扫码结果:
<script setup lang="ts">
import { ref } from 'vue';
import wx from 'weixin-js-sdk';
import { initWechatSdk } from '@/utils/wechat';
const scanResult = ref<string>('');
// 页面加载时初始化JS-SDK(确保扫码接口可用)
initWechatSdk();
/**
* 调用微信扫码接口
*/
const scanQrCode = () => {
wx.ready(() => {
wx.scanQRCode({
needResult: 1, // 1表示直接返回扫描结果,0表示跳转第三方处理
scanType: ['qrCode', 'barCode'], // 可扫描的类型(二维码、条形码)
success: (res: any) => {
// res.resultStr 为扫码结果
scanResult.value = res.resultStr;
},
fail: (err: any) => {
uni.showToast({
title: '扫码失败',
icon: 'none'
});
console.error('扫码失败:', err);
}
});
});
};
</script>
五、项目打包与部署
5.1 打包H5项目
-
右键项目根目录,选择「发行」-「网站-H5手机版」
-
在弹出的打包配置窗口中,填写「网站标题」「网站域名」(即公众号配置的安全域名),点击「发行」
-
等待打包完成,HBuilderX会自动打开打包后的文件夹(默认路径:unpackage/dist/build/h5)
5.2 部署到服务器
将打包后的h5文件夹内容上传到服务器的对应目录(需与公众号配置的安全域名一致),推荐使用FTP工具(如FileZilla)上传:
-
打开FTP工具,连接服务器(输入服务器IP、用户名、密码、端口)
-
将打包后的所有文件(html、css、js、static等)上传到服务器的网站根目录(如「/www/wwwroot/example.com/」)
-
上传完成后,通过域名访问(如「https://example.com」),能正常打开项目则部署成功
5.3 公众号菜单配置(可选)
登录公众号后台,进入「功能」-「自定义菜单」,添加菜单并关联部署后的H5页面链接,用户点击菜单即可直接进入对应页面。
六、常见问题解决
6.1 微信授权失败
-
检查网页授权域名是否正确配置,且已放置校验文件
-
授权链接的redirectUri需编码,且与授权域名一致
-
确保公众号为服务号,订阅号无网页授权获取用户信息的权限
6.2 JS-SDK初始化失败
-
检查JS接口安全域名配置是否正确
-
后端生成签名时使用的url需与当前页面url一致(包括query参数,不包括#后的锚点)
-
确认appId、timestamp、nonceStr、signature参数正确无误
6.3 本地开发跨域问题
-
在manifest.json的H5配置中添加跨域域名
-
使用后端代理解决跨域(如Nginx反向代理、Node.js中间件)
八、扩展功能与优化
8.1 本地调试公众号功能详细注意事项
本地开发公众号H5时,因微信接口需域名验证,直接用localhost无法正常调用授权、JS-SDK等功能,需重点关注以下调试要点:
8.1.1 内网穿透工具使用(必选)
通过内网穿透将本地服务映射为公网域名,推荐使用natapp(操作简单,适合新手):
-
注册登录natapp:https://natapp.cn/,购买免费/付费隧道(免费隧道域名随机,付费可固定)
-
配置隧道:隧道管理→配置,填写本地端口(如HBuilderX运行的8080),其他默认
-
下载natapp客户端,运行命令启动隧道(Windows示例):
natapp -authtoken=你的隧道authtoken -
启动成功后,获取公网域名(如
xxxx.natappfree.cc),将该域名配置到公众号网页授权域名、JS接口安全域名(需提前在natapp后台完成域名备案关联)
8.1.2 微信开发者工具调试
-
下载微信开发者工具:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Web_Developer_Tools.html
-
打开工具,选择「公众号网页项目」,输入内网穿透的公网域名(如
https://xxxx.natappfree.cc),勾选「调试模式」和「不校验域名安全性」(仅本地调试可用) -
调试授权功能时,需登录与公众号绑定的开发者微信号,工具会模拟微信环境触发授权流程
8.1.3 调试避坑要点
-
内网穿透隧道重启后域名可能变化,需重新配置公众号安全域名(免费隧道特性),建议开发期间保留隧道运行
-
授权回调地址需与内网穿透域名一致,且已编码(参考wechat.ts中wechatAuth函数的编码逻辑)
-
调试JS-SDK时,将wx.config的debug设为true,通过开发者工具控制台查看配置错误信息(如签名错误、域名未配置)
-
本地跨域调试:优先在manifest.json的H5配置中添加后端接口域名,若仍有问题,可使用HBuilderX的「代理」功能(manifest.json→H5配置→代理设置)
8.2 更多JS-SDK高频功能实现
扩展原有JS-SDK能力,新增「获取地理位置」「拍照/选图上传」功能,需先更新JS接口列表并封装对应函数。
8.2.1 更新wechat.ts配置与封装函数
// 1. 更新jsApiList,添加新接口
jsApiList: [
'updateAppMessageShareData',
'updateTimelineShareData',
'getLocation',
'scanQRCode',
'chooseImage', // 拍照/选图
'uploadImage' // 上传图片到微信服务器
]
// 2. 新增获取地理位置函数
/**
* 获取用户地理位置
* @param type 坐标类型(wgs84:GPS坐标,gcj02:火星坐标)
*/
export const getWechatLocation = () => {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.getLocation({
type: 'gcj02',
success: (res) => {
const { latitude, longitude } = res; // 纬度、经度
resolve({ latitude, longitude });
},
fail: (err) => {
console.error('获取地理位置失败:', err);
uni.showToast({ title: '获取位置失败,请允许定位权限', icon: 'none' });
reject(err);
}
});
});
});
};
// 3. 新增拍照/选图上传函数
/**
* 拍照/选图并上传到微信服务器
* @param count 最多选择图片数量
*/
export const chooseAndUploadImage = (count: number = 1) => {
return new Promise((resolve, reject) => {
wx.ready(() => {
// 1. 选择图片(拍照/从相册选)
wx.chooseImage({
count,
sizeType: ['original', 'compressed'], // 原图/压缩图
sourceType: ['album', 'camera'], // 相册/相机
success: (chooseRes) => {
const localIds = chooseRes.localIds; // 本地图片ID列表
// 2. 上传图片到微信服务器
wx.uploadImage({
localId: localIds[0], // 上传第一张图片(可循环上传多张)
isShowProgressTips: 1, // 显示进度提示
success: (uploadRes) => {
const serverId = uploadRes.serverId; // 微信服务器返回的图片ID(需传给后端下载)
resolve({ localId: localIds[0], serverId });
},
fail: (err) => {
console.error('图片上传失败:', err);
reject(err);
}
});
},
fail: (err) => {
console.error('选择图片失败:', err);
reject(err);
}
});
});
});
};
8.2.2 页面调用示例(新增pages/extend/extend.vue)
先在pages.json添加路由:
{
"path": "pages/extend/extend",
"style": {
"navigationBarTitleText": "更多功能演示"
}
}
页面代码:
<script setup lang="ts">
import { ref } from 'vue';
import { initWechatSdk, getWechatLocation, chooseAndUploadImage } from '@/utils/wechat';
const locationInfo = ref<any>(null);
const imageUrl = ref<string>('');
// 初始化JS-SDK
initWechatSdk();
// 获取地理位置
const getLocation = async () => {
try {
const res = await getWechatLocation();
locationInfo.value = res;
} catch (err) {
console.error(err);
}
};
// 拍照/选图上传
const chooseImage = async () => {
try {
const res = await chooseAndUploadImage();
imageUrl.value = res.localId; // 显示本地预览图
// 若需上传到自己的服务器,将res.serverId传给后端,由后端从微信服务器下载
console.log('微信服务器图片ID:', res.serverId);
} catch (err) {
console.error(err);
}
};
</script>
8.3 微信支付集成
公众号微信支付需后端配合完成签名生成、订单创建等逻辑,前端核心负责获取支付参数、调起支付、处理支付结果。
8.3.1 公众号支付前置配置
-
登录公众号后台,进入「微信支付」-「商户号关联」,绑定已开通的微信支付商户号
-
配置「支付授权目录」:进入商户号后台→「产品中心」→「开发配置」,添加支付授权目录(需与项目部署域名一致,如
https://example.com/pages/pay/) -
确保项目已部署到公网(本地调试需用内网穿透域名,且已添加到支付授权目录)
8.3.2 前端支付功能实现
- 新增支付相关接口(api/wechat.ts):
/**
* 创建订单并获取支付参数
* @param data { orderId: string, totalFee: number } 订单ID、订单金额(分)
*/
export const createOrderAndGetPayParams = (data: { orderId: string, totalFee: number }) => {
return request({
url: '/api/wechat/pay/createOrder',
method: 'post',
data
});
};
/**
* 查询支付结果
* @param params { orderId: string } 订单ID
*/
export const queryPayResult = (params: { orderId: string }) => {
return request({
url: '/api/wechat/pay/queryResult',
method: 'get',
params
});
};
- 新增支付页面(pages/pay/pay.vue):
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useRoute, useRouter } from 'uni-app';
import { createOrderAndGetPayParams, queryPayResult } from '@/api/wechat';
import wx from 'weixin-js-sdk';
import { initWechatSdk } from '@/utils/wechat';
const route = useRoute();
const router = useRouter();
const orderId = ref<string>(route.query.orderId as string); // 从路由获取订单ID
const totalFee = ref<number>(Number(route.query.totalFee) || 0); // 订单金额(分)
// 初始化JS-SDK(支付需依赖微信环境)
onMounted(() => {
initWechatSdk();
});
/**
* 发起微信支付
*/
const doWechatPay = async () => {
try {
// 1. 获取支付参数(后端返回appId、timeStamp、nonceStr、package、signType、paySign)
const res = await createOrderAndGetPayParams({
orderId: orderId.value,
totalFee: totalFee.value
});
const payParams = res.data;
// 2. 调起微信支付
wx.ready(() => {
wx.chooseWXPay({
appId: payParams.appId,
timestamp: payParams.timeStamp,
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType,
paySign: payParams.paySign,
// 支付成功回调
success: async (payRes) => {
if (payRes.errMsg === 'chooseWXPay:ok') {
// 3. 验证支付结果(前端回调不可信,需调用后端接口查询)
const resultRes = await queryPayResult({ orderId: orderId.value });
if (resultRes.data.success) {
uni.showToast({ title: '支付成功' });
// 跳转订单详情页
router.push(`/pages/order/detail?orderId=${orderId.value}`);
} else {
uni.showToast({ title: '支付结果验证失败,请稍后查询', icon: 'none' });
}
}
},
// 支付失败回调
fail: (err) => {
console.error('支付失败:', err);
uni.showToast({ title: '支付失败:' + err.errMsg, icon: 'none' });
}
});
});
} catch (err) {
console.error('发起支付失败:', err);
uni.showToast({ title: '发起支付失败', icon: 'none' });
}
};
</script>
8.4 模板消息/订阅消息配置与调用
模板消息仅服务号可使用,订阅消息支持所有公众号类型(更推荐使用),用于向用户推送服务通知(需用户主动授权)。
8.4.1 订阅消息前置配置
-
登录公众号后台,进入「订阅消息」-「我的模板」,搜索并选用合适的模板(如“订单支付成功通知”),记录模板ID
-
模板选用后,记录模板的字段名称(如“thing1”对应订单名称,“amount2”对应支付金额)
8.4.2 前端实现订阅消息授权与发送
- 新增订阅消息相关接口(api/wechat.ts):
/**
* 发送订阅消息
* @param data { templateId: string, page: string, data: any } 模板ID、跳转页面、模板数据
*/
export const sendSubscribeMessage = (data: {
templateId: string,
page: string,
data: Record<string, { value: string }>
}) => {
return request({
url: '/api/wechat/subscribe/send',
method: 'post',
data
});
};
- 页面实现授权与发送(以支付成功后发送为例):
// 在pay.vue的支付成功回调中添加订阅消息授权与发送逻辑
const requestSubscribeMessage = async () => {
return new Promise((resolve, reject) => {
wx.ready(() => {
// 1. 请求用户订阅授权(需用户点击允许)
wx.requestSubscribeMessage({
tmplIds: ['你的订阅消息模板ID'], // 模板ID列表
success: (res) => {
// 若用户允许订阅,发送消息
if (res['你的订阅消息模板ID'] === 'accept') {
resolve(true);
} else {
uni.showToast({ title: '未授权订阅消息,无法接收通知', icon: 'none' });
resolve(false);
}
},
fail: (err) => {
console.error('订阅授权失败:', err);
reject(err);
}
});
});
});
};
// 在支付成功的resultRes之后调用
const hasSubscribe = await requestSubscribeMessage();
if (hasSubscribe) {
await sendSubscribeMessage({
templateId: '你的订阅消息模板ID',
page: `/pages/order/detail?orderId=${orderId.value}`, // 点击消息跳转的页面
data: {
thing1: { value: '测试订单' }, // 对应模板的字段名称
amount2: { value: (totalFee.value / 100) + '元' },
time3: { value: new Date().toLocaleString() }
}
});
uni.showToast({ title: '订阅消息发送成功' });
}
8.5 项目优化(H5性能+微信适配)
8.5.1 H5性能优化
-
代码分割与懒加载:Uni-app默认支持路由懒加载,无需额外配置;对于大型组件(如编辑器、图表),使用动态导入(import())减少首屏加载体积
-
静态资源优化:
图片压缩:使用tinypng等工具压缩图片,优先使用webp格式(微信内置浏览器支持) -
静态资源CDN:将图片、字体等静态资源部署到CDN,减少服务器压力,提升加载速度
减少回流重绘:避免频繁操作DOM,使用flex布局替代float;图片提前设置宽高,避免加载后布局偏移
接口优化:合并重复接口请求,添加接口缓存(如用户信息);使用防抖节流处理高频交互(如搜索输入)
8.5.2 微信版本适配与兼容性处理
- 微信版本检测:部分JS-SDK接口需较高微信版本支持,可通过以下代码检测版本:
/**
* 检测微信版本是否满足要求
* @param requiredVersion 要求的版本(如'7.0.0')
* @returns 是否满足
*/
export const checkWechatVersion = (requiredVersion: string) => {
const wechatVersion = navigator.userAgent.match(/MicroMessenger\/(\d+\.\d+\.\d+)/)?.[1] || '';
if (!wechatVersion) return false;
const versionArr = wechatVersion.split('.').map(Number);
const requiredArr = requiredVersion.split('.').map(Number);
for (let i = 0; i < versionArr.length; i++) {
if (versionArr[i] > requiredArr[i]) return true;
if (versionArr[i] < requiredArr[i]) return false;
}
return true;
};
// 使用示例:检测是否支持wx.updateAppMessageShareData
if (!checkWechatVersion('7.0.0')) {
uni.showToast({ title: '微信版本过低,请升级后使用', icon: 'none' });
}
- 适配暗黑模式:微信支持暗黑模式,可通过媒体查询适配:
@media (prefers-color-scheme: dark) {
.container {
background-color: #1a1a1a;
color: #fff;
}
.btn {
background-color: #333;
}
}
- 异常兼容:对未授权、接口调用失败等场景添加友好提示;使用try-catch包裹微信接口调用,避免程序崩溃
七、总结
本教程从零完成了Uni-app+H5公众号项目的搭建,核心流程为:环境准备→项目创建→公众号配置(网页授权+JS-SDK)→核心功能开发→打包部署。重点掌握微信网页授权的code获取与用户信息换取、JS-SDK的初始化与接口调用,即可满足大部分公众号H5项目的开发需求。
本教程已完整覆盖Uni-app+H5公众号开发的核心流程与扩展功能,包括基础搭建、公众号配置、核心功能开发、打包部署,以及微信支付、订阅消息、更多JS-SDK功能、本地调试技巧和项目优化等进阶内容。开发者可根据实际项目需求,基于本教程的代码示例进行扩展迭代。如需进一步深入学习,可参考微信公众号官方文档(https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html)和Uni-app官方文档(https://uniapp.dcloud.net.cn/)。
更多推荐
所有评论(0)