这里介绍了一次在微信WebView中使用Vue作单页应用的过程当中遇到的一些问题,也是比较常见的问题。文末有亮点,但愿你们都来~html
最近由于快过年了,按照微信以往的尿性,小程序的审核老是有各类条条框框,所以为了让活动在线上正常进行且进行版本的迭代,(主要是为了能获得多一些的开发时间)咱们打算采用h5来作活动。前端
微信小程序跳转WebView的问题;vue
wx.config
进行初始化比较优雅的书写方式;jquery
微信签名的一些问题;ios
Vue单页应用在微信浏览器内遇到的一些问题(包含微信支付);web
单页应用内的通讯;算法
首先,咱们先来聊一聊微信跳转到WebView的一些事情,在此以前你们能够先来看看官方给的文档:web-view · 小程序vue-router
普通的跳转没什么好说的,先说说我遇到的问题:vuex
在小程序内进入WebView,我须要把小程序中storage模拟的cookie给带过去,调研了不少资料只获得一个方案,想要从小程序向WebView进行通讯的话只能经过拼接URL,那很绝望啊,那个cookie有多长你知道吗😂?小程序
解决方案:
其实也比较简单,咱们在小程序进入WebView以前会对cookie进行一次操做,将cookie进行md5获得一个较短的字符串,经过这个md5进行拼接获得较短的URL会减小不少的问题。
注意点:
咱们写在URL里边的地址须要encodeURIComponent一下,避免在连接中带有中文字符,不然在 iOS 中打开页面会有白屏的问题。
WebView中的openid和小程序中的openid是不同的,所以各位若是须要作用户关联的话最好用unionid。
跳转的WebView地址须要在mp后台里边进行加白名单,否则没法访问,域名要求是https的。
咱们能够经过微信开发者工具里边公众平台进行开发,你能够在里边调试WebView的页面,jssdk的报错也能够在调试工具中体现,最后没有问题再经过代理的方式到手机上过一遍,这里我用的是Charles进行代理的。
项目在引用JS-SDK的API的时候,必须先注入配置信息,也就是wx.config
,同一个页面(同一个URL)只须要初始化一次就OK了。wx.config
代码以下:
wx.config({
debug: false, // 开启调试模式,调用的全部api的返回值会在客户端alert出来,若要查看传入的参数,能够在pc端打开,参数信息会经过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的惟一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,须要使用的JS接口列表
});
复制代码
具体的信息你们能够看一下文档,这里有一点须要特别提醒你们,写代码的时候,必定要严格按照微信文档里要求去写,大小写,数据类型都要与文档保持一致。微信公众平台
这些都是‘苦口婆心’的话,你要不信,能够试试╮(╯_╰)╭
我在写代码的时候喜欢把不一样的功能写在不一样的方法里边,初始化的函数只作初始化的事情,这样感受比较舒服。
- 在全部微信接口调用前必须保证引入JS-SDK文件,设置JS接口安全域名。
- JS-SDK里有用户触发时才调用的API,有一点须要注意一下,
wx.config
是一个客户端的异步操做,在使用方法的时候会存在因异步致使的时机问题,因此方法最好写在wx.ready
中,wx.config
信息验证成功后会执行wx.ready
方法。- 咱们最好在初始化的时候习惯性的写上
wx.error
与wx.ready
同级,这样以后方法出现问题调试起来也会方便很多,也能够作报错提示。
上边的几个点没问题之后,我来讲一下比较优雅的初始化方法,大概逻辑以下:
首先咱们须要在方法外边封装一个Promise的模板,可是个人项目中也用了Jquery,我就直接用了里边的$.Deferred()
方法
let defer = $.Deferred();
let ready = defer.promise();
复制代码
$.Deferred()
其实就是用来返回一个链式实用对象方法来注册多个回调,里边有多个方法
写好这两个方法之后基本上就完成一半了,激不激动!
按照上边介绍的逻辑,ready
是初始化成功,那么回调就是resolve
。error
是初始化失败,回调就是reject
。而后咱们用defer.promise()
去接收两个状态并返回promise对象,以后你就能够愉快的then()
了。
注意:deferred.promise()
也能够接受一个 target 参数,此时传入的 target 将被赋予 Promise 的方法,并做为结果返回,而不是建立一个新对象。
// Existing object
var obj = {
hello: function( name ) {
alert( "Hello " + name );
}
},
// Create a Deferred
defer = $.Deferred();
// Set object as a promise
defer.promise( obj );
// Resolve the deferred
defer.resolve( "John" );
// Use the object as a Promise
obj.done(function( name ) {
obj.hello( name ); // Will alert "Hello John"
}).hello( "Karl" ); // Will alert "Hello Karl"
复制代码
具体的你能够看看官网的介绍
这一切都准备完了,接下来咱们开始初始化配置
getWxSign(){
wx.config({
debug: false,
appId: ,
timestamp: ,
nonceStr: ,
signature: ,
jsApiList: [],
});
wx.error((err) => {
defer.reject(err);
});
wx.ready(() => {
defer.resolve();
});
}
复制代码
这两步都完成之后,咱们的链式解构就完成了,能够放飞自个人书写。好比我想要获取微信的收货地址,就能够这么写
ready.then(()=>{
wx.openAddress({
success: function (res) {},
fail: function(err) {},
cancel: function() {}
});
});
复制代码
经过这么一封装,你的代码的可读性就会有一个很大提高,至少看着很舒服(自我感受)。
固然在使用这些jssdk的API的时候你们要记得加一个🔒,否则会有屡次调用的状况,可能会出现返回好几回的状况,固然这个我没有试过,你们能够zuo一下。
关于微信签名失效的问题,这里主要是想提一下,由于这一块服务端的代码是另一个小伙伴写的,因此我并无太多的实践,微信签名服务端最好缓存一下access_token。这样能够避免不少没必要要的麻烦。
官方是这么说的:公众平台以access_token为接口调用凭据,来调用接口,全部接口的调用须要先获取access_token,access_token在2小时内有效(7200s),过时须要从新获取,但1天内获取次数有限,开发者需自行存储。
其实在开发之初,服务端的同窗还没写完这一块逻辑的时候,前端的同窗能够这么去调试,先让服务端获取一次配置信息,而后前端暂时先把这一块写死,这样最少两个小时以内是没问题的,能够提升开发的效率。
还有一点,在缓存的有效期内提早去刷新新access_token,这个让服务端的同窗统一控制,不要各自刷新,这样会出现冲突的状况,错误体现为invalid signature。确认这类错的时候咱们须要充分利用官方给的签名校验工具
若是是由于token过时致使的签名失败,基本上在输入token之后就直接提示了,这个时候就要看看是否是服务端的缓存时间出了问题,当时咱们遇到问题的缘由是服务端底层关于时间的计算多*60...
固然出现签名错误还有许多的问题,在确保签名算法没有问题的状况下,可能会以下几种状况:
年少不知微信虎,参数大小写没有按照官方要求书写。重点须要注意一下nonceStr,timestamp两个字段。timestamp的数据类型是String,这个也要注意下。
确认URL是页面完整的url。能够经过location.href.split('#')[0]
确认,目录的话只要填写都按上一级便可。
假如地址为:
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
那么你的URL能够写到上一级
https://mp.weixin.qq.com/debug/cgi-bin
复制代码
config 与获取ticket的AppID不一致。
还有就是服务端若是没有缓存access_token,咱们在调试的时候多刷几下可能就会出现问题了,由于开发的时候我感受刷个几百上千仍是颇有可能的。
前端传递的URL可能会encodeURIComponent处理过的,服务端须要decode。
还有一个服务端获取的URL与前端的URL不一致,这个在手机上打开之后你能够复制一下连接检查一下。
由于这回咱们活动用的是vue的单页应用去完成的,路由用vue-router的history模式,所以会遇到一个比较烦躁的问题,具体的问题我描述一下场景:
在iOS上商品详情页跳转到订单详情页面进行支付,支付页面须要调起两个方法,而个人wx.config是mounted的时候就初始化的,因此每次进入这个页面都会报一个invalid signature,我就纳闷了,无心间发现刷新了一下页面就正常了。有时候不报这个签名问题地址也能使用,可是每次支付的时候他就报地址不对。
最后我上网查了半天我就发现,history模式下,签名使用的URL是刚进入页面时的URL,为了确认是否是这个问题我把每一页的URL都贴出来,还真是都同样,既然问题确认了,那就好解决了。
解决思路:
在进入页面的时候咱们能够先检测一下手机的类型,前边也说了我是在iOS的系统上遇到的问题,在安卓上就没问题,因此无须要对iOS专门处理一下,只要是识别到iOS的机型,那么我就把地址给改了,代码能够参考以下:
// 专门兼容iOS上微信签名的问题
beforeRouteEnter(to, from, next) {
var isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if (isiOS && to.path !== location.pathname) {
location.assign(to.fullPath)
} else {
next();
}
},
复制代码
固然,解决的办法不止这一个,其实有不少的解决方案,就是感受其实不太优雅,当时其实个人备用方案就是要么用a标签进行页面跳转,或者进入这个页面之后,你能够reload
一下来更新URL。选择怎样的方法你们本身选择吧。
首先我说一下场景你们方便理解一下目的。当时在作项目的时候整个项目只有一块功能用到这通讯,当时服务端的童鞋让我不要在表单页面进行提交,由于内容很少,让我把信息带到订单页面结算时一块儿提交,这个其实就是非父子组件之间的通讯,可是这个须要通讯的地方没那么多,引入一个vuex感受过重了,我就直接不考虑这个方案了,就然这个不用,那就直接用eventBus其实也能够,代码以下:
首先咱们须要声明一个eventBus的js文件:
import Vue from 'vue';
var eventBus = new Vue({});
export default eventBus;
复制代码
接下来你须要传递你的值:
import eventBus from 'eventBus/eventBus.js';
let info = {
a: '',
b: ''
};
eventBus.$emit('isVal',info);
复制代码
咱们在提交表单的页面加一个emit
的事件,把填写的内容传出去,接下来咱们就要跳回到订单页面了。
import eventBus from 'eventBus/eventBus.js';
eventBus.$on('isVal',(data)=>{
//....
});
复制代码
使用on
进行接收,这样就完成了,其实也是比较简单的逻辑,没涉及到太多东西,对了这个监听能够放在mounted
或者create
里边,建议用once
就OK了。