1. 在index.html中引用微信接口JS文件
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
2. 请求后端拿回公众号ID,签名等
这里仅涉及前端请求配置,关于jsapi_ticket获取和签名算法都交给后端处理,前端只需要将当前域名发给后端,来获取签名。
这里有两个需要注意的点:
- 一般post请求参数url不需要
encodeURIComponent
传给后端,因为参数是存放在请求体里的;而如果是get请求,需要encodeURIComponent
再传给后端,否则后端没处理的话会读取错误,导致生成的签名失效。 - 注意传给后台的url参数是完整域名地址,包括?后的参数。因此需要
location.href.split('#')[0])
截取#前面的路径,#后面一般都是前端的路由配置。 - 还有的是,微信打开H5页面,一般都会强行加上query参数,例如
你的访问的网址 | 微信展示实际的网址 |
|
|
|
|
|
|
可以看到微信会主动加上from=singlemessage&isappinstalled=0
参数,isappinstalled=0
这参数IOS设备才会添加。而且可以看到有点别扭的感觉,这两个参数直接在hash前面插入了。因为hash后面是前端路由,微信不会主动拼成https://my-web.com/#/user?id=2&from=singlemessage&isappinstalled=0
。
不管怎样,当你的页面地址是https://my-web.com/?from=singlemessage&isappinstalled=0#/user?id=2
,则传url参数https://my-web.com/?from=singlemessage&isappinstalled=0
给后台,不然会导致签名失效,也即location.href.split('#')[0]
。好了,写了有点啰嗦。
3. 微信接口配置
let result = await getWechatJsApiSign({ url: encodeURIComponent(location.href.split('#')[0]) }); // 请求接口
let data = result.data.data;
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.appId, // 必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature,// 必填,签名,见附录1
jsApiList: [ 'updateAppMessageShareData' ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function() { //需在用户可能点击分享按钮前就先调用
wx.updateAppMessageShareData({
title: 'title', // 分享标题
desc: 'desc', // 分享描述
link: location.href,
imgUrl: "https://my-web.com/images/logo.jpg",
success: function () {
}
})
)
配置微信接口以及分享链接,到此就已经实现了。给张图展示一下。
但是你会发现,不管你分享任意一个页面,从分享链接打开都是跳转到主页面,这就尴尬了。这还是之前hash后面的前端路由问题,微信并不会去主动识别跳转hash后面的路由,也就导致每次从分享链接进入的路由都是"/"。
4. 解决分享链接一直是主页面的问题
我们需要把hash后面的路由通过一个参数存起来,然后自定义分享链接携带这个参数。暂且命名这个参数为shareUrl
,当其他用户点击分享链接,判断到路径里有shareUrl
这个参数,则重新拼接路径,再location.href
跳转
let hashBefore = location.href.split("#")[0],
path = location.href.split("#")[1];
// 自定义链接
let linkUrl = hashBefore.includes('?') ? `${hashBefore}&shareUrl=${path}` : `${hashBefore}?shareUrl=${path}`;
// 例如准备分享的页面为:`https://my-web.com/?from=singlemessage&isappinstalled=0#/item?id=2`;
// 则自定义链接为`https://my-web.com/?from=singlemessage&isappinstalled=0&shareUrl=/item?id=2`
wx.ready(function() {
wx.updateAppMessageShareData({
title: 'title',
desc: 'desc',
link: linkUrl,
imgUrl: 'https://my-web.com/img/logo.jpg',
success: function () {
}
})
)
然后在App.vue(基于vue项目)中
created() {
if(location.href.includes("shareUrl")) {
// 注意location.href并不是立刻执行,会继续往下执行代码,再跳转
location.href = location.origin+"/#" + util.getParamFromUrl().shareUrl;
// 将https://my-web.com/?from=singlemessage&isappinstalled=0&shareUrl=/item?id=2
// 拼接成https://my-web.com/#/item?id=2
return;
}
...
}
完整代码
weixin-api.js
封装微信接口配置工具函数
import { getWechatJsApiSign } from '@/api/api';
import util from '@/utils/index.js';
const weixinApiConfigure = async (params) => {
if (!util.IsWeixin || location.href.includes("shareUrl")) { // 包含shareUrl,说明分享链接进入的页面,不需要执行下面代码,等下还要跳转
return;
}
let paramsData = JSON.parse(JSON.stringify(params || "{}"));
const { title, desc, path="/", imgUrl, apiList=[ 'updateAppMessageShareData' ], disabledWeixinConfig=false } = paramsData;
if (disabledWeixinConfig) {
return;
}
let hasApi = {};
for (let item of apiList) {
hasApi[item] = true;
}
// 有配置信息就从本地保存拿,没有就从后台拿
let data = sessionStorage.getItem("WechatJsApiSign");
if (!data) {
let res = await getWechatJsApiSign({ url: encodeURIComponent(location.href.split('#')[0]) });
data = res.data.data;
sessionStorage.setItem("WechatJsApiSign", JSON.stringify(data));
} else {
data = JSON.parse(data);
}
let wx = window.wx;
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.appId, // 必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature,// 必填,签名,见附录1
jsApiList: apiList // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
if (hasApi.updateAppMessageShareData) {
/* 微信分享链接#后面的路径都失效的问题,也即分享链接只能跳转到主页
* 例子:https://my-web.com/?from=singlemessage&isappinstalled=0#/items/detail/1181000
* ?from=singlemessage&isappinstalled=0 这是微信加上去的参数,而且分享链接中不能去掉
* 前端定义个分享url的参数shareUrl,存放#后面的路径
*/
let hashBefore = location.href.split("#")[0];
let linkUrl = hashBefore.includes('?') ? `${hashBefore}&shareUrl=${path}` : `${hashBefore}?shareUrl=${path}`;
wx.ready(function() { //需在用户可能点击分享按钮前就先调用
wx.updateAppMessageShareData({
title: title || '默认', // 分享标题
desc: desc || '默认', // 分享描述
link: linkUrl,
imgUrl: imgUrl || 'https://my-web.com/images/logo.jpg', // 分享图标
success: function () {
}
})
});
}
if (hasApi.hideAllNonBaseMenuItem) {
wx.hideAllNonBaseMenuItem();
}
wx.error(function(res) {
sessionStorage.setItem("WechatJsApiSign", "");
});
}
export default weixinApiConfigure;
在vue路由守卫中,为每个路由页面配置微信接口
import weixinApiConfigure from '@/utils/weixin-api.js';
const routes = [
{
path: '/order',
name: 'cart',
meta: {
weixinConfig: { apiList: ["hideAllNonBaseMenuItem"] }
},
components: {
default: () => import('@/views/order/cart')
}
},
...
]
const RouterModel = new Router({ routes });
RouterModel.afterEach((to, from) => {
weixinApiConfigure({
...to.meta.weixinConfig,
path: to.path
});
})