由于一直在开发公司双十一的各种活动,最近一直也没来得及写笔记。昨天项目成功搞完,今天一大早就迫不及待的来给大家分享一下这次在开发中遇到的一些坑及解决办法。

由于这次双十一的活动主要是微信内传播的小游戏,所以需要用到微信分享,授权等功能。网上关于vue2与微信分享功能的文章挺多,但是内容大多不太全,希望小呆的这篇笔记能够帮助到你。


公众?#25490;?#32622;

如果你们的公众号有专人保管,那么跟他说把安全域名加一下,安全域名用于微信的验证,没有这一步操作,下面的?#21450;?#25645;。比如我们的测试公众号,绑定的就是我们测试服务器的域名。同理,生产也是如此。


后端配置

要想使用微信的JS-SDK功能,需要生成签名,配合appId才能使用,这些步骤通常是由后端生成的。这里省去3000?#32622;?#36848;如何生成签名,反正你找后?#36865;?#23398;就对了。


前端配置

终于轮到我们前端上场了,啰嗦了那么多,下面让我们正式起飞~┏ (゜ω゜)=?

安装微信JS-SDK

首先我们通过npm 安装 微信的js-sdk,?#27604;?#20320;也可以在index.html页面中直接加<script>引用,哪种方式都可以。

npm -install weixin-js-sdk --save

判断是否为微信浏览器

既然我们要用,我们就搞一个通用的mixins嘛,也方便以后在不同的项目中调用。那么,新建一个wxapi.js吧,然后引入之前安装的JS-SDK。既然用微信的JS-SDK,那么肯定非微信浏览器就无法访问该页面啦,所以我们要先写一个判断浏览器的方法。

// wxapi.js
import wx from 'weixin-js-sdk'
const wxApi = {
 /**
 * [isweixin 判断是否微信浏览器]
 */
 isweixin () {
  const ua = window.navigator.userAgent.toLowerCase()
  if (ua.match(/MicroMessenger/i) == 'micromessenger') {
   return true
  } else {
   this.$router.push({path: '/wxkj/isnotWechat'})
   return false
  }
 }
}
export default wxApi

微信JS-SDK初始化

接着,我们写一个微信初始化的方法,用来初始化微信的JS-SDK。该方法接受一个?#38382;?#29992;于传入后续调用的微信功能(如分享,获取地理位置等等)。因为微信的签名等数据是由后?#36865;?#23398;生成的,所以我们需要通过ajax来获取这些数据。这里的this.ajaxGet换成你们自己的ajax方法就好啦。

在获取到后?#36865;?#23398;的数据之后,我们调用wx.config方法,来校验是否可以使用微信的JS-SDK。注意,jsApiList是用来配置可以注册哪些微信功能的,这里举例了2个,一个是分享给朋友,一个是分享到朋友圈,其他功能请到微信JS-SDK文档中自行查看。之后我们调用wx.ready方法,用来处理验证成功后的事件。

 isweixin () {
  ...
 },
// 这里接着上面的代码
/**
* [wxRegister 微信Api初始化]
* @param  {Function} callback [ready回调函数]
*/
wxRegister (callback) {
 let data = {params: {reqUrl: window.location.href}}
 this.ajaxGet(false, '/wxpl/cfgInfo', data).then((res) => {
    wx.config({
     debug: false, // 开启调试模式
     appId: res.appId, // 必填,公众号的唯一标识
     timestamp: res.timestamp, // 必填,生成签名的时间戳
     nonceStr: res.noncestr, // 必填,生成签名的随机串
     signature: res.signature, // 必填,签名,见附录1
     jsApiList: [
        'onMenuShareAppMessage', // 获取“分享给朋友”按钮点击状态及自定义分享内容接口
        'onMenuShareTimeline' // 获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
     ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
    })
 }).catch((error) => {
    console.log(error)
 })
 wx.ready((res) => {
    // 如果需要定制ready回调方法
    if (callback) {
     callback()
    }
 })
}

微信分享到朋友圈

初始化之后,我们接着往下写,这里拿分享到朋友圈举例。写一个方法,用来调用微信的分享朋友圈。因为不同的页面分享的内容不一样,成功或者失败后的回调函数也不同,所以我们这里做个简单配置。传一个?#38382;?/p>

// ?#30001;?#38754;的代码
/**
* [ShareTimeline 微信分享到朋友圈]
* @param {[type]} opstion [分享信息]
* @param {[type]} success [成功回调]
* @param {[type]} error   [失败回调]
*/
 ShareTimeline (opstion) {
  wx.onMenuShareTimeline({
   title: opstion.title, // 分享标题
   link: opstion.link, // 分享链接
   imgUrl: opstion.imgUrl, // 分享图标
   success () {
    // ?#27809;?#25104;功分享后执行的回调函数
    opstion.success()
   },
   cancel () {
    // ?#27809;?#21462;消分享后执行的回调函数
    opstion.error()
   }
 })
}

页面中调用微信功能

通过以上代码,我们封装了一个简单的微信JS-SDK功能,那么在页面中如何调用这些封装好的方法呢。首先我们编写一个方法用来作为wx.ready中的callback,然后在通过配置opstion的方式,将自定义信息注入到之前封装好的通用分享方法中。实现随用随调,灵活配置的微信功能。

//a.vue
import wxapi from '../mixins/wxapi.js'

export default {
 mixins: [wxapi],
 mounted () {
  this.wxRegister(this.wxRegCallback)
 },
 methods: {
  /**
  * [wxRegCallback 用于微信JS-SDK回调]
  */
  wxRegCallback () {
     this.wxShareTimeline()
  },
     /**
  * [wxShareTimeline 微信自定义分享到朋友圈]
  */
    wxShareTimeline () {
   let opstion = {
    title: '胡小呆&曹小萌的情侣博客', // 分享标题
    link: 'http://www.pvmy.icu',      // 分享链接
   imgUrl: 'http://www.pvmy.icu/wordpress/wp-content/themes/wordpress_thems/images/lib/logo.png'// 分享图标
   success: function () {
      alert('分享成功')
   },
   error: function () {
       alert('分享失败')
   }
  }
  // 将配置注入通用方法
  this.ShareTimeline(opstion)
  },
 }
}

微信授权

微信授权的功能其实我们前端只需要存储好?#27809;?#30340;uid和token即可。验证的逻辑一般都是后端那边进行的。授权的方法同样归类为微信操作,所以代码也封装在wxapi.js中,可以参考如下代码:(hostName是当前域名,因为开发,测试,生产的域名不一样,所以做了变量配置)

 /**
 * [isWxAuth 微信授权]
 */
 isWxAuth () {
  let localUid = localStorage.getItem('localUid')
  let localToken = localStorage.getItem('localToken')
  if (!localToken) {
   let token = this.$route.query.token
   let uid = this.$route.query.uid
   if (token) {
    localStorage.setItem('localToken', token)
    localStorage.setItem('localUid', uid)
   } else {
    // 将url?#21990;?#21518;传给后端,解决微信过滤Vue hash模式 #被过滤的问题
    var u = encodeURIComponent(window.location.href)
    window.location.href = hostName + '/wxpl/oauth?forwardUrl=' + u
   }
  }
 }

思路也很简单,每次进入页面的时候就会判断本地存储中是否有token,如果没有,去url中查看是否带有token?#38382;?#26377;的?#25353;?#21040;本地。没有的话将当前页面地址?#21990;?#21518;传给后端,进行授权。

但是这样做,token过期后,页面一直取过期的token,就会导致授权一直失败。所以我们还需要在token过期之后,将旧的token从本地存储中删掉,更新为新的token。我是这么做的:(因为调用后端接口需要我将token传给他们验证是否过期,所以后端会返回一个字段告诉是否需要重新授权)

这里有一点需要注意: 就是如果当前url中带着?#38382;?#27604;如www.pvmy.icu/#hello?uid=200&token=abcdefg这?#20013;?#24335;,如果我们还是取window.localtion.href,授权的就是www.pvmy.icu/#hello?uid=200&token=abcdefg这个页面,和www.pvmy.icu/#hello是不同的,出现的问题就是页面一直在不断的往url后面加uidtoken,一直跳授权,导?#28388;?#24490;环。

所以我这里用域名 + 路径 + vue的path来拼装url,这样就可以解决发送给后端的url错误的问题。

// 通用ajax方法中
...
 // 微信token是否过期 这里的字段是后端返回的,如果为true就?#24471;鱰oken已经过期
 if (response.data.invalid_auth == 'true') {
  localStorage.removeItem('localToken')
  localStorage.removeItem('localUid')
  var u = encodeURIComponent(hostName + window.location.pathname + '#' + this.$route.path)
  window.location.href = hostName + '/wxpl/oauth?forwardUrl=' + u
 } else {
  resolve(response.data)
 }
...

踩坑分享

1.签名验证失败

解决思路:(1)先查看是否是因为字母大小写等原因造成的。(2)之后查看是否因为路由的变化导致签名校验失效。用小呆的这种方式可以避免因路由变化导致校验失败的问题。因为每次路由变化后都会重新生成签名进行校验。

2.分享出去的URL被微信插入其他字符

比如我分享的url是www.pvmy.icu/#hello,但是实际在微信中打开的链接是www.pvmy.icu?from=xxxxxxxx/#hello

解决思路:暂无。目前测试,加入微信的?#38382;?#20043;后,页面可以正常打开。

3.hash模式,微信授权会将url中的#过?#35828;簦?#23548;致授权的token和url不一致

解决思路?#33322;玼rl进行转码后在传给后端,即可解决。

4.授权url错误导致的一直重复授权的死循环

解决思路: url不用window.location.href,采用拼装方式处理

好啦,到这里这篇笔记就写完了,如果?#38405;?#26377;帮助,就给本文点个赞吧。如果能把博客收藏起来时不时转转,那就更好啦~

(PS:其实这篇文章应该昨天发布的,但是昨天写到一半,就被产品插了其他事情进来,笔记没保存,干别的事儿去了,结果下午测试过程中,chrome?#35272;?#20102;…o(╥﹏╥)o,只好今天重新写一遍了)