前言
笔者近期做了一个h5前端项目,需要用到微信相关的功能。因为是第一次做涉及到微信的功能,总是在踩坑和试错,故在此总结记录一下。
遇到的困难
- 所有微信相关的功能不能在本地调试,好像是可以实现,但是很麻烦。所以我们采取了改了代码直接放到正式的服务器上,用正式的域名
- 想用微信提供的接口必须先引入js,然后wx.config初始化配置
- 跳转小程序的按钮样式难调
技术栈 比较简单,但是需要引入
- jQuery
- weui
- jweixin
一、网页授权 获取code
想要获取当前用户的微信信息,必须拿到这个code。逻辑是前端打开一个链接,在回调页面里的url里(是这样的:redirect_uri/?code=CODE&state=STATE)可以获取code和携带的参数state。redirect_uri/?code=CODE&state=STATE。
我写了以下的方法:
- 封装了openAuthorizePage方法打开回调页面
- 封装了从url获取code的方法
- 注意坑:调试的时候的code不显示到url中,所以用手机把链接发送到电脑上没用。但是打印可以出来
封装了openAuthorizePage方法
/**
* 打开验证页的方法
* @param {*} url 回调页面的路径
* @param {*} state 携带的参数。自己规定的 传 '1' 则立即执行支付的方法
*/
function openAuthorizePage(url, state) {
console.log("进入验证页", url, state)
let response_type = "code" //就这样写
state = state || "STATE" // 携带的参数
let scope = "snsapi_base" // 两种情况,snsapi_base不跳页,snsapi_userinfo跳页
var router = encodeURIComponent("这里是正式环境的域名" + url)// 记得encodeURIComponent
const jumpPath = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${router}&response_type=${response_type}&scope=${scope}&state=${state}#wechat_redirect`
console.log("跳转url", jumpPath)
window.location.href = jumpPath
}
//转码——
function getUrlCode(key) {
let url = window.location.href
console.log("当前url===", url)
//如果有就直接截取code
if (url.indexOf("?") != -1) {
let obj = urlToObj(url)
console.log("getUrlCode()---" + key, obj[key])
if (obj[key]) {
return obj[key]
}
}
return ""
}
function urlToObj(str) {
var obj = {}
var arr1 = str.split("?")
var arr2 = arr1[1].split("&")
for (var i = 0; i < arr2.length; i++) {
var res = arr2[i].split("=")
obj[res[0]] = res[1]
}
return obj
}
调用方法获取code
// 回调页面这样获取code
var code = sessionStorage.getItem("code")// 从缓存里取有没有这个code
$(function () {
let code1 = getUrlCode("code")// 从url取有没有code
if (code1) {// 如果url里有code就把它放到缓存里。
sessionStorage.setItem("code", code1)
code = code1
}
})
二、根据code获取openid和微信用户信息
- 后台写了一个接口,若以前注册过此平台,则直接返回code和微信用户信息;若以前没有注册过,则只返回openid,前台需要把openid存到缓存,并跳到手机号验证码登录页
- 此业务是选择商品点击支付的按钮就调用登录的方法,登录完就自动调用支付的方法。
- 注意坑:code使用了一次以后就会失效,5分钟以后也会失效。所以本次开发中只使用一次code获取oppenid
- openid用于登录和支付
封装了commonAdoptClick方法来决定是先去登录还是支付。
/**
* 支付按钮点击事件
* @param {*} page 当前页面url
* @param {*} params 调支付接口需传参
* @param {*} state 回调页面里的参数。自行判断 '1'的时候直接去调支付的接口
*/
function commonAdoptClick(page, params, state) {
if (!wxUser || !openid) {
// 如果没有user信息或者openid就去登录,否则就生成订单去支付
weChatLogin(page, params, state)
} else {
// 处理支付业务的方法(第三部会展示)
makeAdot(params, page)
}
}
/**
* 微信公众号登录
* @param {*} page 回调页面的路径
* @param {*} params 支付需要的参数
* @param {*} state 携带的参数。自己规定的 传 '1' 则立即执行支付的方法
*/
function weChatLogin(page, params, state) {
if (code) {
if (openid && !wxUser) {
// 拿到openid了去登录页注册
window.location.href = "login.html"
} else {
// getApi是封装的请求后台的方法
getApi("post", "后台登录接口", { code: code }).then((res) => {
if (res.status) {
// 之前注册过,拿code登录成功
localStorage.setItem("wxUser", JSON.stringify(res.data))
localStorage.setItem("openid", res.data.wechat_openid)
openid = res.data.wechat_openid
params.user_id = res.data.userId
// 登录成功后直接就可以支付了
// 处理支付业务的方法
makeAdot(params, page)
} else {
// 之前没注册过,生成的openid 去登录页
localStorage.setItem("openid", res.data.openid)
window.location.href = "login.html"
}
})
}
} else {
// 获取code(上文第一步的方法)
openAuthorizePage(page, state)
}
}
在页面调用
// 从缓存取oppenid,weUser,
var wxUser = localStorage.getItem("wxUser")
var openid = localStorage.getItem("openid") || ""
// 写好支付需要的参数,和当前的url,调用commonAdoptClick
let params = {
// 支付业务需要的参数
}
const page = '当前页面的url'
commonAdoptClick(page, params, "1")
三、支付功能
- 微信支付 官方文档
- 微信支付V2的开发 官方文档
- 本次开发使用的是微信支付v2开发,JSAPI调起支付
封装了生成订单、获取支付需要的传参、调微信支付的方法
// 生成订单
function makeAdot(params, page) {
getApi("post", "生成订单的后台接口", params).then((res) => {
console.log("res", res)
if (res.status && res.data) {
let data = res.data
console.log("开始支付")
payPet(data.order_no, page)
} else {
$.alert(res.msg || "操作失败")
}
})
}
// 订单支付
function payPet(order_no, url) {
let param1 = {
user_id: userId,
order_no,
type: 3, //类型 1-APP 2-小程序 3-公众号JSAPI 不传默认app
openid: openid,
}
console.log("订单支付入参", param1)
getApi("post", "获取微信支付需要的参数", param1).then((res) => {
if (res.status) {
// 调微信的支付
const data = res.data
sessionStorage.setItem("signPackage", JSON.stringify(data))
onBridgeReady(data, order_no)
} else {
$.alert(res.msg || "查询失败")
}
})
}
function onBridgeReady(data, order_no) {
WeixinJSBridge.invoke(
"getBrandWCPayRequest",
{
appId: data.appId, //公众号ID,由商户传入appid, //
timeStamp: data.timeStamp, //时间戳,自1970年以来的秒数
nonceStr: data.nonceStr, //随机串
package: data.package,
signType: data.signType, //微信签名方式:
paySign: data.paySign, //微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
$.confirm({
title: "提示",
text: "恭喜您支付成功,您可以去小程序-“XXX"查看,
onOK: function () {
//点击确认
//点击确认后的回调函数
window.location.href = "jump_mp.html"// 此页面写了跳转小程序的方法
},
onCancel: function () {},
})
} else {
$.alert("支付失败")
}
}
)
}
四、跳转小程序
- h5跳转小程序的官方文档
- 先通过config接口注入权限验证配置
- 使用此标签跳转小程序:wx-open-launch-weapp
调用后台接口拿到wx.config需要的参数,然后wex.config初始化配置
var myurl = location.href.split("#")[0]// 当前页面url
getApi("post", "get-jssdk后台接口名", { url: myurl }).then((res) => {
if (res.status) {
console.log("微信初始化接口结果:", res)
let datad = res.data
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
appId: datad.appId, // 必填,公众号的唯一标识
timestamp: datad.timestamp, // 必填,生成签名的时间戳
nonceStr: datad.nonceStr, // 必填,生成签名的随机串
signature: datad.signature, // 必填,签名,见附录1
jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"], // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
openTagList: ["wx-open-launch-weapp"],
})
wx.error(function (res) {
$.alert(res.msg || "微信config失败")
})
// initShare(param)
wx.ready(function () {
console.info("ready")
var btn = document.getElementById("launch-btn")
btn.addEventListener("launch", function (e) {
console.log("success")
})
btn.addEventListener("error", function (e) {
console.log("fail", e.detail)
})
})
}
})
html代码
- 注意坑:按钮的样式难调,默认就是原生的按钮样式很丑,写到style标签里或者行内样式才生效。而且有的属性不生效。所以最后没有用这一版跳转小程序的代码,而是放了二维码图片让用户扫。
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<wx-open-launch-weapp id="launch-btn" username="gh_开头的小程序对应的名" path="">
<script type="text/wxtag-template">
<style>
.btn{
padding:12px;
background-color: #1aad19;
color: #fff;
}
</style>
<button class="btn">打开小程序</button>
</script>
</wx-open-launch-weapp>
五、自定义分享内容功能
- 微信自定义分享给朋友、朋友圈等 官方文档
- 同上一步一样,必须先wx.config
- 在自定义分享功能写上这个jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"]
// 判断是否是微信浏览器
function is_weixn() {
var ua = navigator.userAgent.toLowerCase()
if (ua.match(/MicroMessenger/i) == "micromessenger") {
console.log("微信浏览器")
return true
} else {
console.log("不是微信浏览器")
return false
}
}
function initWxConfig(param) {
if (is_weixn()) {
console.log("微信初始化")
var myurl = location.href.split("#")[0]
getApi("post", "后台获取wx.config所需的参数", { url: myurl }).then((res) => {
if (res.status) {
console.log("微信初始化接口结果:", res)
let datad = res.data
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
appId: datad.appId, // 必填,公众号的唯一标识
timestamp: datad.timestamp, // 必填,生成签名的时间戳
nonceStr: datad.nonceStr, // 必填,生成签名的随机串
signature: datad.signature, // 必填,签名,见附录1
jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"], // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
})
wx.error(function (res) {
$.alert(res.msg || "微信config失败")
})
// initShare(param)
wx.ready(function () {
console.info("ready")
//需在用户可能点击分享按钮前就先调用
wx.updateAppMessageShareData(param)
//需在用户可能点击分享按钮前就先调用
wx.updateTimelineShareData(param)
})
}
})
}
}
在页面调用
let param = {
title: "分享标题", // 分享标题
desc: "分享描述", // 分享描述
link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: data.box_image, // 分享图标
success: function () {
// 设置成功
console.log("分享设置成功")
},
}
initWxConfig(param)