vue2引入微信JSSDK
可以参照:https://ask.dcloud.net.cn/article/35380
vue3引入微信JSSDK,会报错require is not defined
- npm install weixin-js-sdk -S
使用:import * as jWeixin from 'weixin-js-sdk'
使用场景,uni-app
在store中添加state:
- openid: "", // 公众号的openid
- accessToken: "", // 公众号的access_token
- baseOpenidKey: "DOOR_MANAGE_H5_OPENID", // 用户的openid缓存Key
mutations 添加commit方法:
- setOpenid(state, params){
- state.openid = params.openid
- state.accessToken = params.access_token
- // 缓存更新
- uni.setStorage({
- key: state.baseOpenidKey,
- data: params,
- success: (result) => {
- // 保存成功
- // console.log("openid和access_token缓存更新成功", params);
- },
- fail: () => {
- uni.showToast({
- title: '存储openid和access_token数据失败',
- icon:'none'
- });
- }
- })
- },
action中添加dispatch方法:
- /**
- * 初始化获取openid
- */
- initOpenid: async function({
- dispatch,
- commit,
- state
- }, params) {
- return await new Promise((resolve, reject) => {
- uni.getStorage({
- key: state.baseOpenidKey,
- success:async (res) => {
- // console.log("从缓存中初始化openid", res.data);
- commit('setOpenid', res.data)
- resolve(res.data.openid);
- },
- fail: (err) => {
- reject("获取openid缓存信息失败,仅提示");
- }
- })
- })
- },
再添加一个自定义JS文件:wechat.js
- // #ifdef H5
- import * as jWeixin from 'weixin-js-sdk'
- import GraceRequest from '@/Grace6/js/request.js'
- import GraceRequestConfig from "@/custom/graceRequestConfig.js"
- // 需要调用的微信api列表
- export const WXAPI = [
- // 'chooseWXPay',
- // 'updateAppMessageShareData',
- // 'updateTimelineShareData',
- // 'onMenuShareAppMessage',
- // 'scanQRCode',
- 'getLocation'
- ]
- export default {
- /**
- * 判断是否在微信中
- */
- isWechat() {
- var ua = window.navigator.userAgent.toLowerCase();
- if (ua.match(/micromessenger/i) == 'micromessenger') {
- //console.log('是微信客户端')
- return true;
- } else {
- //console.log('不是微信客户端')
- //以下是我项目中所需要的操作其他,可以自定义
- uni.showModal({
- title: '提示',
- content: '请在微信浏览器中打开',
- showCancel: false,
- confirmColor: '#00875a',
- success: function(res) {
- if (res.confirm) {
- // console.log('用户点击确定');
- } else if (res.cancel) {
- // console.log('用户点击取消');
- }
- }
- });
- return false;
- }
- },
- /**
- * H5下获取openid,这里需要传参两个值
- * @param {Object} params
- * const params = {
- * code: '', // 交换了之后的code
- * appid: '公众号的唯一标识',
- * }
- */
- async getH5AuthCode(params) {
- return new Promise((resolve, reject) => {
- if (!this.isWechat()) {
- reject('不是微信客户端')
- return
- }
- const appid = params.appid
- if(!appid) {
- reject('缺少appid')
- return;
- }
- // 从本地读取是否已存在openid
- uni.store.dispatch('initOpenid').then(openid => {
- reject('已有openid,无需授权' + openid)
- }).catch(err => {
- let aaa = window.location.search
- if(!aaa){
- let url = GraceRequestConfig.URL + window.location.pathname + window.location.hash //这里使用完整地址
- // console.log('跳转回头的url', url)
- url = encodeURIComponent(url)
- // 已认证服务号,默认拥有scope参数中的snsapi_base和snsapi_userinfo 权限
- const locationHref = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + appid + '&redirect_uri='+url+'&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect'
- window.location.href = locationHref
- }else{
- const queryString = aaa.split('?')[1];
- if (!queryString) {
- uni.showToast({
- title: '缺少参数',
- icon: 'error'
- });
- reject('缺少参数')
- return
- }
- const params = queryString.split('&');
- // console.log('跳转的参数', params)
- const result = {};
- params.forEach(param => {
- const [key, value] = param.split('=');
- // result[key] = decodeURIComponent(value);
- result[key] = value
- });
- if(!result.code){
- uni.showToast({
- title: '缺少code参数',
- icon: 'error'
- });
- reject('参数错误,缺少code')
- return
- }
- resolve(result.code)
- }
- })
- })
- },
- /**
- * H5下获取openid,这里需要传参两个值
- * @param {Object} params
- * const params = {
- * code: '', // 交换了之后的code
- * appid: '公众号的唯一标识',
- * secret: ‘公众号的appsecret', // 因为每个appid不同,所以这里需要带参
- * }
- */
- async getH5OpenId(params) {
- return new Promise((resolve, reject) => {
- if (!this.isWechat()) {
- reject('不是微信客户端')
- return;
- }
- // 参考文档
- // https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
- const openid = uni.store.state.openid
- if(openid) {
- resolve(openid)
- return
- }
- if(!params.appid) {
- reject('缺少appid')
- return;
- }
- if(!params.secret) {
- reject('缺少密钥')
- return;
- }
- uni.store.dispatch('initOpenid').then(openid => {
- console.log('获取的本地openid', openid)
- resolve(openid)
- }).catch(err => {
- if(!params.code) {
- reject('请先获取授权')
- return;
- }
- //获取授权
- GraceRequest.post(
- '/api_WXGetOpenid', {
- // post 数据
- data: params
- },
- ).then(res => {
- // 返回,直接返回数据,忽略code等其他信息
- const {
- status,
- data
- } = res
- console.log('通过code交换的值', data)
- uni.store.commit('setOpenid', data)
- resolve(data.openid)
- }).catch(err => {
- console.log('H5通过code交换openid接口有误', err);
- reject(err)
- })
- })
- })
- },
- /**
- * 通过config接口注入权限验证配置
- * @param {Object} cb 需要执行的函数
- */
- initJssdk(cb) {
- //获取当前url然后传递给后台获取授权和签名信息
- var url = encodeURIComponent(window.location.href.split('#')[0]); //当前网页的URL,不包含#及其后面部分
- console.log('微信注入传递的URL是:', window.location.href.split('#')[0]);
- // return
- // 注入config权限配置
- GraceRequest.post(
- '/api_WXConfig', {
- // post 数据
- data: {
- url: url
- }
- },
- ).then(res => {
- // 返回,直接返回数据,忽略code等其他信息
- const {
- status,
- data
- } = res
- // https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#1
- jWeixin.config({
- debug: true, // 是否开启调试模式
- appId: data.appId, // 必填,公众号的唯一标识
- timestamp: data.timestamp, // 必填,生成签名的时间戳
- nonceStr: data.nonceStr, // 必填,生成签名的随机串
- signature: data.signature, // 必填,签名,见附录1
- jsApiList: WXAPI
- })
- // 本地环境测试使用,里面信息是测试号的appid和签名
- // jWeixin.config({
- // debug: true,
- // appId: 'wx451eff21c6c0d938',
- // timestamp: 1659065946,
- // nonceStr: 'dzklsf',
- // signature: 'd2ada1c92409e14c9e720ed58056dcd3800ab0a7',
- // jsApiList: ['scanQRCode']
- // })
- // 本地环境测试结束
- if (cb) {
- cb()
- }
- jWeixin.error(function(res){
- // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
- console.log('注入权限有误', res)
- });
- }).catch(err => {
- console.log('获取公众号Config接口注入权限有误', err);
- })
- },
- //微信扫码
- scanQRCode: function(callback) {
- if (!this.isWechat()) {
- //console.log('不是微信客户端')
- return;
- }
- this.initJssdk(function(res) {
- jWeixin.ready(function() {
- jWeixin.scanQRCode({
- needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
- scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
- success: function(res) {
- // console.log(res);
- callback(res);
- },
- fail: function(res) {
- callback(res)
- },
- });
- });
- });
- },
- //在需要定位页面调用
- getLocation: function(callback) {
- if (!this.isWechat()) {
- console.log('不是微信客户端')
- return;
- }
- this.initJssdk(function(res) {
- jWeixin.ready(function() {
- jWeixin.getLocation({
- type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
- success: function(res) {
- // console.log(res);
- callback(res)
- },
- fail: function(res) {
- console.log(res)
- },
- });
- });
- });
- },
- //打开位置
- openlocation: function(data, callback) {
- if (!this.isWechat()) {
- //console.log('不是微信客户端')
- return;
- }
- this.initJssdk(function(res) {
- jWeixin.ready(function() {
- jWeixin.openLocation({ //根据传入的坐标打开地图
- latitude: data.latitude,
- longitude: data.longitude
- });
- });
- });
- },
- //选择图片
- chooseImage: function(callback) {
- if (!this.isWechat()) {
- //console.log('不是微信客户端')
- return;
- }
- //console.log(data);
- this.initJssdk(function(res) {
- jWeixin.ready(function() {
- jWeixin.chooseImage({
- count: 1,
- sizeType: ['compressed'],
- sourceType: ['album'],
- success: function(rs) {
- callback(rs)
- }
- })
- });
- });
- },
- //微信支付
- wxpay: function(data, callback) {
- if (!this.isWechat()) {
- //console.log('不是微信客户端')
- return;
- }
- // this.initJssdk(function(res) {
- // jWeixin.ready(function() {
- jWeixin.chooseWXPay({
- appId: data.appId,
- timeStamp: data.timeStamp, // 支付签名时间戳
- nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
- package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
- signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
- paySign: data.paySign, // 支付签名
- success: function(res) {
- // console.log(res);
- callback(res)
- },
- fail: function(res) {
- callback(res)
- },
- });
- // });
- // });
- },
- //自定义分享 这里我统一调用了分享到朋友和朋友圈,可以自行定义
- share: function(callback) {
- if (!this.isWechat()) {
- //console.log('不是微信客户端')
- return;
- }
- this.initJssdk(function(res) {
- jWeixin.ready(function() {
- //我的分享配置由后台返回,可以自定义
- http.get({
- url: 'getShareInfo'
- }).then(res => {
- const { shareInfo } = res.data;
- jWeixin.updateAppMessageShareData({ //分享给朋友
- title: shareInfo.title,
- desc: shareInfo.description,
- imgUrl: shareInfo.image,
- link: shareInfo.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
- success: function() {
- // 用户确认分享后执行的回调函数
- callback(res);
- }
- });
- jWeixin.updateTimelineShareData({ //分享到朋友圈
- title: shareInfo.title,
- desc: shareInfo.description,
- imgUrl: shareInfo.image,
- link: shareInfo.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
- success: function() {
- // 用户确认分享后执行的回调函数
- callback(res);
- }
- });
- });
- });
- });
- },
- }
- // #endif
在App.vue的onShow即使用:
- // 页面初始化获取openid
- uni.store.dispatch('initOpenid')
- npm i -S weixin-js-sdk
引入:
- import wx from 'weixin-js-sdk'
踩坑一:
微信分享:
QAQ1、router模式请改为hash:
- export default new Router({
- mode: 'hash',
- base:'/test/', // 根路径,可自定义
- routes: [
- // 用户部分
- {
- path: '/',
- name: 'userPetSelect',
- components: {
- main: userPetSelect,
- }
- },
QAQ2、关于网上资料说,IOS的请求页面权限需要使用入口记录第一次的url(在改为哈希模式后,这条不成立):
关于分享后的链接被微信添加了微信的自定义参数,如:
http://test.aaa.bbbb.com/?from=singlemessage&isappinstalled=0#/details?id=2
// 原本链接 http://test.aaa.bbbb.com/#/details?id=2
找了资料发现有小伙伴提供的一个方案很好用,在#前面加一个?号
- wxShare({state,commit},params) {
- let desc = params.desc, //分享的简介
- title = params.title,//params.title, //分享的标题
- shareUrl = params.link, //分享的链接
- imgUrl = params.imgUrl; //分享的缩略图
- let link = window.location.href; // 请求JSSDK的页面路径
- link = link.split('#')[0]; //签名需要传当前页面的url
- let linkEndString = link.charAt(link.length-1);
- if(linkEndString == '?'){
- link=link.substring(0,link.length-1)
- }
- shareUrl = link + "?#"+ shareUrl; //重新拼接分享的链接
- alert(shareUrl);
- request.post(global.shareUrl,{url:link}).then(response => {
- if(!response) {
- return false;
- }
- // 请求成功后保存
- let appId = response.appId;
- let timeStamp = response.timeStamp;
- let nonceStr = response.nonceStr;
- let signature = response.signature;
- wx.config({
- debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
- appId: appId,
- timestamp: timeStamp,
- nonceStr: nonceStr,
- signature: signature,
- jsApiList: [
- 'checkJsApi',
- 'onMenuShareTimeline', //分享到朋友圈
- 'onMenuShareAppMessage', //分享给朋友
- 'onMenuShareQQ', //分享到QQ
- 'onMenuShareWeibo', //分享到腾讯微博
- 'onMenuShareQZone', //分享到QQ空间
- ]// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
- });
- let share_config = {
- "imgUrl": imgUrl,//分享图,默认当相对路径处理,所以使用绝对路径的的话,“http://”协议前缀必须在。
- "desc" : desc,//摘要,如果分享到朋友圈的话,不显示摘要。
- "title" : title,//分享卡片标题
- "link": shareUrl,//分享出去后的链接,这里可以将链接设置为另一个页面。
- "success":function(){
- //分享成功后的回调函数
- commit("changeIfShare",true);
- let instance = Toast('分享成功');
- setTimeout(() => {
- instance.close();
- }, 1000);
- },
- 'cancel': function () {
- // 用户取消分享后执行的回调函数
- let instance = Toast('您已取消分享');
- setTimeout(() => {
- instance.close();
- }, 1000);
- }
- };
- wx.ready(function() {
- //分享给朋友
- wx.onMenuShareAppMessage(share_config);
- wx.onMenuShareAppMessage(share_config);
- wx.onMenuShareTimeline(share_config);
- wx.onMenuShareQQ(share_config);
- wx.onMenuShareWeibo(share_config);
- wx.onMenuShareQZone(share_config);
- })
- wx.error(function(res){
- // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
- alert.log(res);
- });
- });
- },
上面的放在action方法中,回调以后 可以通过变量值currentIfShare来控制
- const state = {
- currentIfShare:false, //当前页面是否已分享
- }
- const mutations = {
- changeIfShare(state,value){
- state.currentIfShare = value;
- },
- }
方法使用:
- data() {
- return {
- },
- mounted() {
- this.wxShare(); //执行微信分享
- },
- computed:{
- ifShare(){
- return this.$store.state.common.currentIfShare;
- },
- },
- watch:{
- ifShare(){
- if(this.ifShare){
- this.closePopup(); //如果ifShare参数为true,关闭遮罩层
- }
- },
- },
- methods: {
- openPopup(val) {
- this.popupVisible = true;//打开遮罩
- },
- closePopup(val) {
- //关闭遮罩层的同时,将当前分享状态设为false,分享成功后回调为true
- this.popupVisible = val;
- this.$store.commit('common/changeIfShare', false);
- },
- wxShare() {
- let defaultImg = this.$store.state.common.LOGOImg;console.log(defaultImg);
- var shareUrl = "/yoyo/user-homepage/"+sessionStorage.getItem("userId"); //分享链接
- let params = {
- title: 'yoyo个人博客', //分享的标题
- desc:'想要站在巨人的肩膀上,就从关注他开始!', // 分享的简介
- link: shareUrl, //分享链接
- imgUrl: defaultImg //分享默认图片
- };
- this.$store.dispatch("common/wxShare",params); // 进入方法,调取分享SDK接口
- }
- },
PS:改为哈希模式后,发现不需要判断设备了,该方法通用
QAQ3:路由中包含code参数?
在微信浏览器中,如果要获取用户授权,会自带一个code参数,这种情况,vue的分享路由就会出现问题,针对code 改一下截取:
- wxShare({state,commit},params) {
- let desc = params.desc, //分享的简介
- title = params.title,//params.title, //分享的标题
- shareUrl = params.link, //分享的链接
- imgUrl = params.imgUrl; //分享的缩略图
- let link = window.location.href; // 请求JSSDK的页面路径
- link = link.split('#')[0]; //签名需要传当前页面的url
- request.post(global.shareUrl,{url:link}).then(response => {
- if(!response) {
- return false;
- }
- // 请求成功后保存
- let appId = response.appId;
- let timeStamp = response.timeStamp;
- let nonceStr = response.nonceStr;
- let signature = response.signature;
- wx.config({
- debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
- appId: appId,
- timestamp: timeStamp,
- nonceStr: nonceStr,
- signature: signature,
- jsApiList: [
- 'checkJsApi',
- 'onMenuShareTimeline', //分享到朋友圈
- 'onMenuShareAppMessage', //分享给朋友
- 'onMenuShareQQ', //分享到QQ
- 'onMenuShareWeibo', //分享到腾讯微博
- 'onMenuShareQZone', //分享到QQ空间
- ]// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
- });
- let code = global.GetQueryString('code'); // 定义GET参数
- if(code !=null && code.toString().length>1)
- {
- link = link.split('?')[0];//如果有code值要截取?之前
- }else{
- link = link.split('#')[0]; //签名需要传当前页面的url
- }
- let linkEndString = link.charAt(link.length-1);
- if(linkEndString == '?'){
- link=link.substring(0,link.length-1)
- }
- shareUrl = link + "?#"+ shareUrl; //重新拼接分享的链接
- let share_config = {
- "imgUrl": imgUrl,//分享图,默认当相对路径处理,所以使用绝对路径的的话,“http://”协议前缀必须在。
- "desc" : desc,//摘要,如果分享到朋友圈的话,不显示摘要。
- "title" : title,//分享卡片标题
- "link": shareUrl,//分享出去后的链接,这里可以将链接设置为另一个页面。
- "success":function(){
- //分享成功后的回调函数,改变当前分享状态为true,默认为false
- commit("changeIfShare",true);
- let instance = Toast('分享成功');
- setTimeout(() => {
- instance.close();
- }, 1000);
- return true;
- },
- 'cancel': function () {
- // 用户取消分享后执行的回调函数
- let instance = Toast('您已取消分享');
- setTimeout(() => {
- instance.close();
- }, 1000);
- return false;
- }
- };
- wx.ready(function() {
- //分享给朋友
- wx.onMenuShareAppMessage(share_config);
- wx.onMenuShareAppMessage(share_config);
- wx.onMenuShareTimeline(share_config);
- wx.onMenuShareQQ(share_config);
- wx.onMenuShareWeibo(share_config);
- wx.onMenuShareQZone(share_config);
- })
- // wx.error(function(res){
- // // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
- // alert.log(res.errMsg);
- // });
- });
- },
获取地址栏的GET参数方法:
- GetQueryString(name){
- //js获取地址栏的GET参数
- var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
- var r = window.location.search.substr(1).match(reg);
- if(r!=null)return unescape(r[2]); return null;
- },
在安卓的分享成功后的回调中,不仅有自己配置的分享成功,还会出现安卓本身的,已分享字样,故,增加判断设备 :
踩坑二:微信支付
不需要使用预先SDK的接口支持,直接引入SDK后,加点击事件:
- wx.chooseWXPay({
- appId: data.appId,
- timestamp: data.timeStamp, // 支付签名时间戳,最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
- nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
- package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
- signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
- paySign: data.paySign, // 支付签名
- success: function(res) {
- // 支付成功后的回调函数
- alert("支付成功");
- this.intoByType();
- }
- });
这里对这个timestamp字段,有一个争议,看到有的文档中是S大写,有的是小写,在vue的脚手架上项目开启了debug后,发现该字段赋值为underfined,在微信的debug中,也是timeStamp,在JS中却要使用小写的,具体看使用情况吧!