【Copy攻城狮日志】踩坑小程序之canvas的显示层级问题

33次阅读

共计 2473 个字符,预计需要花费 7 分钟才能阅读完成。

Created 2019-4-3 18:29:53 by huqiUpdated 2019-4-3 19:12:22 by huqi

↑开局一张图,故事全靠编↑
从一个需求说起
狼叔 @i5ting 曾说过:“单纯讲技术进阶点意义不大,脱离场景都是耍流氓”。今天,依旧从一个需求说起。什么需求呢?一个二维码,一个二次确认弹窗。这里的二维码是前端生成的,二维码下边有个 button,点击 button 调起自定义的弹窗组件。依旧是很简单的需求,但是对于“资深”的 Copy 攻城狮来说,除了布局,其他的就只能去 Copy 了。分析了一下可能需要的代码,就开始 ’ 刷刷刷 ’ 一顿 CP(Copy&Paste) 操作猛如虎,结果跑下代码发现 error 二百五。特别是真机跑的时候,问题特别多。像这次的问题,开发者工具上压根就发现不了,幸好习惯性真机预览,不然一通 push 就等着失业了。还是坑在基础不牢固,文档看得不深入,对小程序原生组件应该注意的事项把握不准,才会掉入这个非常基础的坑。
(图片来源于网络)
canvas 生成二维码
通常来说,遇到这种类似的需要,我都会先找找被人造的轮子,尝试一下,有合适的就直接拿过来用了。这次用的是 @yingye 大佬开源的 weapp-qrcode, 这个 js 应该是借鉴了 jquery-qrcode 和 node-qrcode, 有兴趣的同学可以研究研究,生码的逻辑应该是类似的,只是小程序中没有 DOM 操作,都是利用 canvas 来实现的。具体怎么实现,各位看客可以直接看相关的源码或文档。我的实现:
wxml
<canvas style=”width: 140px; height: 140px;” canvas-id=”myQrcode”></canvas>
wxss
canvas{
display: block;
margin: 0rpx auto; /** 居中 **/
}
js
drawQrcode({
width: 140, // 必须,二维码宽度,与 canvas 的 width 保持一致
height: 140, // 必须,二维码高度,与 canvas 的 height 保持一致
x: 0, // 非必须,二维码绘制的 x 轴起始位置,默认值 0
y: 0, // 非必须,二维码绘制的 y 轴起始位置,默认值 0
canvasId: ‘myQrcode’, // 非必须,绘制的 canvasId
typeNumber: 10, // 非必须,二维码的计算模式,默认值 -1
text: ‘ 您的二维码内容 ’, // 必须,二维码内容
callback(e) {// 非必须,绘制完成后的回调函数
console.log(‘e: ‘, e)
}
})
二维码效果:

canvas 使用限制
当我页面如上图一样。底部有个按钮。点击唤起自定义的弹窗组件,在开发者工具上呈现的效果十分正常。但是在真机上就会出现文字开头的不和谐现象。canvas 直接覆盖住了自定义组件。通过翻阅文档,您会发现官方特别写出了 Bug&Tip:

3.tip:请注意原生组件使用限制。
4.bug: 避免设置过大的宽高,在安卓下会有 crash 的问题

然后点开原生组件使用限制,就会发现本 B.U.G 的根本原因了:
原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。
也就是说 canvas 会覆盖自定义的 dialog 组件。那么怎么解决呢?我的思路是“曲线救国”– 将 canvas 转成 image。一不做二不休,撸起袖子,开干!

将 canvas 转换成 image
既然原生组件(camera、canvas、focus 时的 input、live-player、live-pusher、map、textarea、video)这么牛逼,那就打压一下,去掉他们高贵的身份,豁免他们享有的特权,彻底 ge 他们的命,恢复他们的平民身份。按照这个思路,开始一步一步来实现 wxml
<canvas wx:if=”{{!renderImg}}” style=”width: 140px; height: 140px;” canvas-id=”myQrcode”></canvas>
<image wx:else mode=”scaleToFill” class=”image” style=”width: 140px; height: 140px;” src=”{{renderImg}}”></image>
js
data: {
renderImg: ”
},
onLoad: function(){
drawQrcode({
width: 140, // 必须,二维码宽度,与 canvas 的 width 保持一致
height: 140, // 必须,二维码高度,与 canvas 的 height 保持一致
x: 0, // 非必须,二维码绘制的 x 轴起始位置,默认值 0
y: 0, // 非必须,二维码绘制的 y 轴起始位置,默认值 0
canvasId: ‘myQrcode’, // 非必须,绘制的 canvasId
typeNumber: 10, // 非必须,二维码的计算模式,默认值 -1
text: ‘ 您的二维码内容 ’, // 必须,二维码内容
callback(e) {// 非必须,绘制完成后的回调函数
console.log(‘e: ‘, e)
if(e.errMsg == ‘drawCanvas:ok’) {// 新增转图片
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: 140,
height: 140,
canvasId: ‘myQrcode’,
success: function(res) {
me.setData({renderImg: res.tempFilePath});
}
});
}
}
})
}
以上将 canvas 替换成 image,不过遇到闪烁的问题,这是 wx:if 特有的,这里通过取巧的办法,只改了 canvas 的样式:wxss
canvas{
display: block;
margin: 0rpx -9999px; /** 占位解决二维码闪屏 **/
}
image{
display: block;
margin: 0rpx auto; /** 居中 **/
}
至此,已填了这个 canvas 显示层级过高的坑。

如您有更好的方案,欢迎提出指正!如您觉得文章解决了您的问题,欢迎打赏

正文完
 0