uni-app微信公众号H5分享踩坑
最近项目中使用uni-app写了一款H5的微信公众号开发,其中有一个活动详情的分享功能的踩坑经历,解决起来也是遇到了一些坑,话不多说,上代码。
本人有前端交流群:群里妹子多多,大佬多多,有兴趣的可以私聊我进群
第一块是分享,第二部分是微信公众号跳转网页授权流程
我们先来看一波微信官方文档
一:我们第一步是需要绑定域名,这个在微信公众开发平台可以绑定
二: 引入js文件,我是在项目中直接引入的文件
var jweixin = require('jweixin-module')
三:config的权限注入验证,这里直接调取后台接口获取到对应的参数写进去就行
compomentDidmount() {
let url = `${location.origin}${location.pathname}${location.search}`;
return this.$http.request({
url: `/h5/mobile/WXShare`,
method: 'post',
data: {
url: url
}
}).then(res => {
if (res.code === 200) {
jweixin.config({
debug: false,
appId: res.data.appId,
timestamp: res.data.timestamp,
nonceStr: res.data.nonceStr,
signature: res.data.signature,
jsApiList: res.data.jsApiList
});
}
})
},
这里的url传给后台一般只需要location.href就能满足需要,但是后来遇到一些问题,这个等下再说,继续看流程。
四:通过ready处理成功的验证,我这里是后台直接返回的我需要配置的jsApiList,所以就不需要在手动填写。
let url =
`${location.origin}${location.pathname}#/pages/look_activity/look_activity?activity_id=${this.activity_id}&invite_id=${invite_id}&spreader_id=${spreader_id}`;
let data = {
title: '', // 分享标题
desc: '', // 分享描述
link: url, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: '', // 分享图标
success: function () {
// 用户点击了分享后执行的回调函数
}
};
jweixin.updateAppMessageShareData(data)
// 分享到朋友圈
jweixin.updateTimelineShareData(data)
注意:这里的路径必须要和公众号配置的一样,当然我这里是路径分享出去以后要带参数,所以路径后面 ? 可以不用一致,此处只贴出来关键代码。
这里有一个问题就是
${location.origin}${location.pathname}#/
// 如果我直接在上方url写成 let url = ${location.href}
// 这时候我的分享出去的标题等等都会失效
// 然后找了一下问题,就在原代码的路径前加入 ${location.origin}${location.pathname}?#/
// 这个时候我的分享就能正常运行
就在昨天用户从首页直接访问进来分享的时候就出现了之前的问题,当时我拿手机测试的都是正常的,还以为是客户苹果手机的问题,然后就开始找问题,终于在我同事大佬的帮助下找到了问题所在。
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分)
这里官方给的解释是 当前网页的URL,不包含#及其后面部分
// 这就是我为什么必须要在路径后面加 ? 号才能正常访问的问题,所以我就干脆直接点在进入程序的时候就改变url后面的规则,从而在任何一个地方分享都能正常分享
刚开始想的是在APP.vue里面进来就改变url地址
if (location.href.indexOf('?') == -1) {
location.href = '?' + location.hash
return
}
这个方法,如果在编辑器运行都是正常的,换成真机就会失败,所以在进入到分享的页面的时候,就直接改变 let url = `${location.origin}${location.pathname}${location.search}`;
到这里就能正常的使用了,还有分享的时候微信会有自带的参数,需要解析。本人项目中没用到这一需求所以就没有进行处理,不过还是给方法给你们贴出来好了。
encodeURLComponent(window.location.href) 搞定!
微信公众号网页授权登录流程
当时在写这一部分的时候,应为是初次写不太熟所以走了很多弯路,现在把代码给发出来,就当是回顾一下代码好了。
话不多说,先上文档哈哈哈哈 微信网页授权文档
文档上面写的很清楚,直接按照文档一步一步来就行
1 第一步:用户同意授权,获取code
2 第二步:通过code换取网页授权access_token
3 第三步:刷新access_token(如果需要)
4 第四步:拉取用户信息(需scope为 snsapi_userinfo)
5 附:检验授权凭证(access_token)是否有效
话不多说上代码!!!
Store->user.js Vuex
state: {
// 用户code值
code: '',
// 用户信息
userInfo: { },
// 返回跳转链接
backUrl: '',
},
mutations:{
// 获取code
getCode(state) {
state.code = ''
//要跳转的url
let url = `${location.origin}${location.pathname}?#/pages/login/login`;
//在这里根据官方文档进行 解析
let local = encodeURIComponent(url)
//这部分就是文档要求的了
let params = '&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect';
let loginUrl = `${baseConfig.baseUrl}?appid=${baseConfig.APPID}&redirect_uri=${local}${params}`;
uni.setStorageSync('backUrl', location.hash);
window.location.href = loginUrl; // 跳转即可!!
}
},
actions: {
// 判断用户token是否有效
checkToken(context) {
// 获取用户信息
api.getUserInfo().then(res => {
if (res.code == 200) {
this.userInfo = res.data;
uni.setStorageSync('userInfo', res.data);
} else {
context.commit('getCode');
}
});
},
// 判断用户是否登录
checkAuth(context, path) {
let token = uni.getStorageSync('userToken');
if (!token && path !== 'pages/login/login') {
// token 不存在肯定没有登录
context.commit('getCode');
} else {
if (path !== 'pages/login/login') {
// token 存在验证token有效性
context.dispatch('checkToken');
}
}
}
},
到这里就是vuex需要做的操作了,那么下边,我们是做了一个login的过度页去过度一下,话不多说,程序员用代码交流
login.vue
<template>
<view class="wrap">
<image class="loading" src="http://pjserver.huasukeji.net/uploads/loading.gif"></image>
<text>正在登录请稍后...</text>
<view>如果长时间没有跳转,<text class="doLogin" @click="goIndex">请点击这里</text></view>
</view>
</template>
methods:{
//这里就对code进行处理
getParam(path, name) {
var reg = new RegExp("(^|\\?|&)" + name + "=([^&]*)(\\s|&|$)", "i");
if (reg.test(path))
return unescape(RegExp.$2.replace(/\+/g, " "));
return "";
},
init() {
let code = this.getParam(location.href, 'code') //获取授权成功返回的code
if (code) {
//这里就不做解释了,想必大家都能看的懂
this.doLogin(code);
}
},
doLogin(code) {
let params = {
code: code
}
this.$api.login(params).then(res => {
if (res.code && res.code === 200) {
uni.setStorageSync('userToken', res.data.token);
history.replaceState({}, null, `${location.origin}${location.pathname}`);
let backUrl = uni.getStorageSync('backUrl');
if (backUrl) {
backUrl = backUrl.replace('#', '')
} else {
backUrl = '/';
}
this.$api.getUserInfo().then(res => {
if (res.code == 200) {
this.userInfo = res.data
uni.setStorageSync('userInfo', res.data)
uni.reLaunch({
url: backUrl
})
} else {
uni.showToast({
icon: 'none',
title: res.msg
})
}
})
} else {
uni.showToast({
icon: 'none',
title: '登录失败'
})
}
})
},
//这里是担心用户在本login页面时间过长,所以做了路由跳转的处理
goIndex() {
history.replaceState({}, null, `${location.origin}${location.pathname}`);
uni.reLaunch({
url: '/pages/index/index'
});
},
// 截取code
getUrlCode() {
var url = location.search
this.winUrl = url
var theRequest = new Object()
if (url.indexOf("?") != -1) {
var str = url.substr(1)
var strs = str.split("&")
for (var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = (strs[i].split("=")[1])
}
}
return theRequest
},
// 可以直接拿来用
}
这里对history.replaceState做一下解释 基于replaceState() 是修改了当前的历史记录项而不是新建一个,所以无论用户在当前页面多少次的点开不同的子页面,当点击返回时,都会回到https://固定页面。
应为考虑到分享出去时候 肯定不能让用户登录成功以后在跳转到首页,所以做的需求就是用户进来的时候直接判断有没有登录,没有登录的话点击登录还是在本页面保持不变!!
最后在APP.vue调用方法
onLaunch: function(e) {
this.$store.dispatch('checkAuth', e.path);
},
到这里就搞定了!
@手动艾特我的两位后台同事,在项目中给予我很大的帮助
本人只是分享在项目中从陌生到踩坑的一些经历,帮助没有做过此需求的大佬们一个参考,如果可以请帮忙点个赞,写文章很累,白天加班,晚上分享。
@有什么不明白或者不足之处,请留言告诉我,谢谢!