微专业前端开发教程 pdf |
前端开发 菜鸟教程 |
前端开发进阶教程 |
一、 长按图片为base64的图片,识别图中的二维码时,base64的字符个数有限制
经过测试大于大概为258286字符(大约500KB)的时候,在识别图时可以弹出正常的菜单,但是点击菜单项“识别图中二维码”则无反应。
需求背景: 拓展业务时,都会生成一个二维码页面用于分享给别人; 而二维码页面包含有,二维码图片,公司logo图,背景图,动态产品介绍文案 等构成的一个页面。
用于分享出去的东西最好的预期是,能把整个页面转换为图片分享出去效果是最好的,而不单单只分享一个二维码图片。所以就有以下需求点需要解决:
利用微信内置的长按功能即可以实现以上需求。在长按后,弹出来的菜单中,可以自己选择“保存为图片”,或者点击“识别图中二维码”直接进入推广页,或者也可以直接发送给朋友。
根据以上需求点,那么问题来了。
页面如何转换为图片呢?
通过html2canvas把页面转换为canvas,然后在通过canvas.toDataURL方法转换为base64图即可
用到的技术为html2canvas
如何使用呢?
直接在自己项目中安装
yarn add html2canvas -D
在项目中引用
import html2canvas from ‘html2canvas’
// 把页面生成为base64图
html2canvas(document.body).then((canvas) => {
const base64Image = canvas.toDataURL(‘image/png’)
console.log(`转换出的base64图为:${base64Image}`)
})
把转换出来的base64图,替换掉页面即可,用户是无感知的。
那么问题来了,通过canvas.toDataURL
转换出来的base64字符过长,超出了微信base64字符限制,这怎么办呢?
可以利用canvas.toDataURL 转换为image/jpeg 然后添加第二个参数,改变图片质量,把字符将到限制以下即可。
canvas.toDataURL(‘image/jpeg’, 0.3) // 在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量
更多详细的toDataURL方法的使用可以参考MDN文档
二、页面首次登录发起的微信静默登录后,后台重定向回到当前页面,要点击两次返回才能回到上一个页面问题。
要分析整个问题,得先理解微信的静默登录的流程是如何的,流程如下:
微信静默登录的地址为:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=[企业号appId]&redirect_uri=[后台回调url]&response_type=code&scope=snsapi_base&state=[前端页面url]#wechat_redirect
- 第一 ,当页面请求某个后台接口时,后台接口会返回一些东西,让你知道用户未登录;通常的做法是,后台会返回状态码401,然后前端根据401状态吗,执行location.replace([微信静默登录地址]),让页面加载这连接就会执行静默登录。
- 第二,加载以上连接后,微信会把响应的一些参数code和参数state指定的前端页面拼接到传入的后台回调url,然后执行这个后台url请求。
- 第三,请求后台时,后台会根据拼接传给他的参数,去获取用户的openid,和access_token,成功后,会重定向回到state参数指定的前端页面url。
原因分析:
后台重定向是无法替换掉历史记录的,所以导致这个问题。
对于这个问题的误解:当发起微信静默登录时,采用location.replace()时,一直以为,为什么不会替换掉历史记录,问题的考虑点就错了,问题点不在这,因为问题点是重定向不会替换掉历史记录。所以当用户登录成功后,点击第一次返回,会回到当前页,再次点击返回时,才能回到上一个页面,所以会出现,点击2次返回才能回到上一个页面问题。
那么问题来了,如何解决这个问题呢?
假如有两个页面A(不需要登录态),B(需要登录态)
首先得分析一下页面的历史记录如下:
- 当进入页面A时,历史记录为1,当点击跳转到B页面时,执行了微信静默登录,此时历史记录+1 即为2。
- 然后登录成功后重定向回到B页面,此时历史记录再+1 即为3了。
我们可以重定向回到B页面时,还未进入到B页面,就让历史回退history.go(-2)
到A页面(此时历史记录为1),然后A页面在根据一些参数来判断,跳转到B页面(此时的历史记录为2),即可实现当点击B页面可以直接回到A页面。
ps:这里我的项目主要用到了中间页进行登录了。没有中间页的情况,直接history.go(-1)
即可。
还是直接上代码吧,代码(截取的是自己vue项目的一个实现,部分代码)如下:
vue项目为单页面应用,所以把逻辑放到全局路由守卫(当进入A,B页面时都会执行,即进入A或B路由时,首先会执行的逻辑判断
// 静默登录时,传给state的前端url参数,后边加了一个参数”?isLogin=true” 添加了这个参数,同时也解决了另一个静默登录遇到的坑,后续会讲到。
// const stateUrl = encodeURIComponent(‘http://www.demo1.com/?isLogin=true#/pageA’);
// 连接如: `https://open.weixin.qq.com/connect/oauth2/authorize?appid=[企业号appId]&redirect_uri=[后台回调url]&response_type=code&scope=snsapi_base&state=${stateUrl}#wechat_redirect`
vue.beforeEach((to, from, next) => {
if (!window.localStorage) {
next()
}
const prevUrl = localStorage.getItem(‘prevUrl’)
if (prevUrl) {
// 假如存在这个参数,说明是从静默登录成功后的页面跳回来的。即这里,判断为是从B页面跳回来的。
localStorage.removeItem(‘prevUrl’)
next({
// 跳回静默登录成功后的页面,这里指的即是跳回到B页面。
path: `${prevUrl.split(‘#’)[1]}`,
query: {
cache: false,
},
})
}
if (/\?isLogin=true/g.test(location.href)) {
localStorage.setItem(‘prevUrl’, `${location.hash.split(‘?’)[0]}`) // 添加这prevUrl参数用于判断是否存在是从B跳到A的,相当于保存了B页面的连接,即静默登录成功后进入的页面连接。
history.go(-2) // 回退到A页面
}
next()
})
三、iphone6和iphone6s中发现,静默登录后页面不刷新,或者白屏
假如进入A页面时发起静默登录,成功登录后回调到A页面,要是A页面连接不变,A页面就不会刷新,导致,假如刚进入A页面,还未渲染DOM时,就发起静默的登录,重定向回来时,看起来就是白屏效果,或者假如你传给state的参数大于128字节时(即字符长度为64)。超过的话,会被截取掉。
想要预防state大于限制被截取掉,可以把前端的回调地址不要放在state参数里,而是自己取一个参数拼接放在后端的回调参数redirect_uri里即可,然后在跟后端约定就好,拼接如下:
const feUrl = ‘http://www.demo1.com/?isLogin=true#/pageA’; // 前端地址
const authCallbackUrl = `${apiSourceDomain}/wechat/zlAuthCallback.jhtml?redirectUrl=${encodeURIComponent(state)}`; // 后端地址
location.replace(`https://open.weixin.qq.com/connect/oauth2/authorize?appid=[企业号appId]&redirect_uri=${authCallbackUrl}&response_type=code&scope=snsapi_base&state=${stateUrl}#wechat_redirect`); //发起微信静默登录
即静默登录成功后,后台到时候想要302重定向回来前端页面,取的参数值应该为上边的redirectUrl参数了,而不是微信拼接的state参数了,这个跟后台约定好即可。
解决方案:
发起静默登录时,在参数state指定的前端回调页面连接里,加入任意参数即可。添加如下:
const feUrl = encodeURIComponent(‘http://www.demo1.com/?isLogin=true#/pageA’)
location.replace(
`https://open.weixin.qq.com/connect/oauth2/authorize?appid=[企业号appId]&redirect_uri=[后台回调url]&response_type=code&scope=snsapi_base&state=${feUrl}#wechat_redirect`,
)
四、ios左右边缘滑动返回前进页面动画与h5用户自定义页面切换动画冲突问题
导致滑动切换页面时执行了ios的动画之后又执行自定义动画。看起来就是闪了一下自定义动画。
解决方案:
监听左右滑动手势和touchstart事件清除掉自定义动画即可。
同时加入滑动后多少ms后恢复动画,不然滑动后就真的没有自定义动画了 ,已防止用户不是边缘滑动时清除掉的自定义动画恢复。
多少ms 后恢复 建议设置为切换动画执行时间的两倍即可。
上边为什么要监听touchstart事件呢,因为经过测试发现滑动边缘返回或前进时,不一定执行滑动事件,因为封装的滑动事件是有最小距离的,超过才执行的。
然后又为了防止用户触摸屏幕时会执行touchstart事件从而导致切换动画清除掉,在click事件发生时要回复动画。
截取vue项目中的部分代码如下:
// <transition :name=”transitionName”>
// <router-view @click.native=”onClick” v-swipe=”{fn:onSwipe, trigger: ‘touchstart’}” ></router-view>
//</transition>
export default {
data:{
return {
routeMap:{
count:0,
‘/’:0,
},
transitionName:”,
touchHandler:null,
}
}
watch:{
$route(to, from){
// 切换路由,判断是前进页面,或后退页面,相应改变 this.transitionName = ‘next’;
// 或 this.transitionName = ‘prev’;
const toIndex =this.routeMap[to.path];
const fromIndex =this.routeMap[from.path];
if(toIndex !==undefined){
if(!fromIndex ||parseInt(toIndex,10)>parseInt(fromIndex,10)){
this.transitionName=’next’;
}else{
this.transitionName=’prev’;
}
}else{
this.routeMap.count+=2;
this.routeMap[to.path]=this.routeMap.count;
// 第一个页面不需要动画,因为每个子路由的from都是根路由(即使你第一个访问的是子路由)
if(from.path!==’/’){
this.transitionName=’next’;
}
}
// 清除掉自定义动画
this.touchHandler&&this.touchHandler();
}
}
methods:{
…
// 监听点击事件
onClick(){
this.touchHandler=null;// 恢复自定义动画
},
//监听向左向右滑动,和touchstart事件
onSwipe(){// 解决ios系统版本在11.0以上,滑动会执行原生动画和
vue自定义动画冲突问题
if(Device.isIOS()&&(Device.iosVersionCompare(‘11.0’)!==-1)){// 大于11.0
this.touchHandler=()=>{
this.transitionName=”;// 清除掉自定义动画
};
this.Timer&&clearTimeout(this.Timer);
this.Timer=setTimeout(()=>{// 恢复自定义动画
this.touchHandler=null;
},2000);
}
},
…
}
}
ps: 这个不是微信里的坑,但是也一起记录了,触摸事件可以自己添加,vue-touch触摸插件,上边的v-swipe指令我是自己在项目里通过 vue.derective(‘swipe’,{…}) 这种方式自己添加的。
参考
HTMLCanvasElement.toDataURL()
html2canvas
微信网页授权
前端开发教程网 |
web前端开发 整套视频教程 |
前端开发视频教程百度云 |
评论前必须登录!
注册