说明
描述:在此次换装游戏的结果分享页中,由于用户点击『分享到朋友圈』按钮后,将生成一张图片并保存到本地相册中(原因见传送门),而这张图片是需要根据用户所选装扮、得分进行动态绘制的,所以我采用了微信canvas绘图相关的api。现在将此次快速开发中使用canvas踩的坑做个小结,方便自己随时查阅回顾。
提示:我觉得canvas是一个很好玩的绘图 API ,虽然这次学习和开发时间很短,自己也简单入了canvas的门,但希望自己后面有时间可以深入去学习和研究canvas~~~
canvas中的单位问题
在canvas中绘制的单位都是px,但由于不同屏幕的像素比不同,在小程序中样式我们使用的单位是rpx,所以在canvas中就需要把rpx换成对应的px;由于rpx可以根据屏幕宽度进行自适应,规定屏幕宽为750rpx,所以rpx换算成px的公式是:
1rpx = 屏幕宽度px / 750rpx
当前元素rpx / 750rpx = 绘制使用的宽度px / 屏幕宽度px
则:
绘制使用的宽度px =( 屏幕宽度px / 750) * 当前元素rpx
屏幕宽度可以使用wx.getSystemInfoSync()
获取。
所以例如在样式中canvas宽度为650rpx,那么在canvas中绘制使用的宽度就是:(屏幕宽度 * 650)/ 750 ;
封装代码如下
function rpx2px(num) {
var reg = /^\d+(?=\.{0,1}\d+$|$)/;
if (!reg.test(num)) {
throw Error('px2rpx参数必须为数字!');
}
var info = wx.getSystemInfoSync();
var screenWidth = info.screenWidth;
return parseFloat((screenWidth * num / 750).toFixed(2));
}
查看小程序的官方文档叙述。
真机上页面绘制的canvas中的图片元素不显示
问题描述
在结果分享页,点击『分享到朋友圈』按钮后,将绘制一张canvas,绘制出的效果图如下。
但直接用接口返回的图片地址(或网络图片)在canvas中绘制结束后,canvas中的图片元素却不显示(是空白),文字内容能正常显示。
解决办法
法1 使用wx. getImageInfo
wx. getImageInfo()
中res.path
会返回图片的本地路径,即相当于把网络图片下载到本地存入缓存;
然后再调用canvasContext.drawImage
绘制图像到画布,最后用canvasContext.draw
(将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中),转成图片后,就可以保存了。
法2 使用wx.downloadFile【我们实际采用的】
原因
微信开发工具中可以正常显示canvas中绘制出的图片,是因为模拟器上可以拿到缓存,真机不行。
参考代码和思路
wx.getImageInfo({
src: ‘htttp://****’,
success: function (res) {
console.log(res.path)
// TODO 绘制分享canvas图draw
// TODO 绘制成功后,把canvas转化成图片wx.canvasToTempFilePath
// TODO 转成功后,自动保存图片到系统相册wx.saveImageToPhotosAlbum
}
})
推荐文章:
https://blog.csdn.net/hushilin001/article/details/79136052
微信小程序button样式修改
<button class="result-btn" open-type="share" type="default" size="mini">
<text class='btn-text'>邀请ta来PK</text>
</button>
重写wx的<button>
按钮的样式
微信小程序button去掉边框
.result-btn::after{
border: 0px solid #bfbfbf;
}
设置按钮里的文字上下垂直居中
.result-btn{
height: 68rpx;
line-height: 68rpx !important;
}
设置按钮的文字全显示(不换行)
.btn-text {
white-space: nowrap;
}
使用cover-view解决微信小程序canvas等原生组件层级问题
直接在canvas上使用view、image等是不行的,因为查看微信小程序canvas的API底部Bug&Tip有一句话:
canvas 组件是由客户端创建的原生组件,它的层级是最高的,不能通过 z-index 控制层级。
所以直接在canvas上使用view等是没有效果的!即使使用z-index改变z轴也没用。而且在微信开发者工具中调试时层级是没有问题的,但是在手机上canvas就会处于最高层级。
解决办法
可使用控件cover-view
。
覆盖在原生组件之上的文本视图,可覆盖的原生组件包括map、video、canvas、camera、live-player、live-pusher,只支持嵌套cover-view、cover-image。
<canvas canvas-id="shareCanvas" style="bottom:-{{screenHeight*2}}px;width:{{screenWidth}}px;height:{{screenHeight}}px;" >
<cover-view class="forbidden-scroll result-img-box">
<cover-image src="{{canvasImgUrl}}" style="width:{{dWidth}}px; height:{{dHeight}}px;"></cover-image>
</cover-view>
</canvas>
更多详情见cover-view文档介绍
提示:但在结果分享页,我并没有使用cover-view
,因为这个页面包含的标签元素种类太多,比如form、button,而且由于埋点的原因又只能用form、button标签,但cover-view
内只支持嵌套cover-view、cover-image,所以无法采用上述方法。我采用的是让canvas标签定位的bottom足够远(bottom:-{{screenHeight*2}}px),使其不在屏幕可视范围内。虽然笨拙,但是也算是解决方法之一了
2018.7.24 任务2后的小结
小程序中遮罩层的滚动穿透问题
问题描述
实现遮罩层效果时,会出现滚动穿透的问题,即在遮罩层上滑动时(position:fixed),遮罩层后面的页面依旧可以滚动。
解决方案
添加 catchtouchmove 事件来阻止冒泡。
<!--视频播放浮层-->
<view wx:if="{{currentVideoUrl}}" catchtouchmove="forbiddenScroll" bindtap="closeVideoPop" class="video-box box box-tb box-center-center pop-mask">
<view catchtap="stopBubble">
<video src="{{currentVideoUrl}}" autoplay='{{videoAutoplay}}' controls='{{videoControls}}' objectFit='contain' class="video">
</video>
</view>
</view>
备注
在其他移动端开发时ipone手机上此方法可能会滑动卡顿,解决办法:在需要滚动的元素上加上下面的样式代码。
-webkit-overflow-scrolling : touch; //可以让页面在Native端滚动时模拟原生的弹性滚动效果
查看更多相关文章
仅点击视频外的区域才关闭遮罩的方法
问题描述:只能点击视频周围的黑层遮罩才能关闭视频层
解决办法:我采用的是点击video标签时阻止向上冒泡(catchtap)执行closeVideoPop方法。
视频在弹窗中的bug
bug描述
ios下,使用catchtouchmove仍然无法解决滑动bug(即在video上滑动时,仍然触发了页面的滚动)猜测可能是video是微信再客户端生成且层级最高的原因,但android下无此bug(疑问???)。所以单独针对ios进行处理。
解决原理
未打开视频弹窗时,记录下页面滚动的距离videoScrollNum;当打开视频弹窗后,一但在视频标签上监听到页面有滚动就设置页面滚动距离值为videoScrollNum,以达到禁止滚动的效果。
onload:function(){
wx.getSystemInfo({
success: function (res) {
// 判断是否是ios系统
if (res.system.toLowerCase().indexOf('ios') > -1
|| res.platform.toLowerCase().indexOf('ios') > -1) {
that.setData({
isIos:true
});
}
}
});
},
onPageScroll:function(e) {
var that = this;
// ios:打开视频弹窗后,在<video>上滑动时禁止页面滚动
if (this.data.isIos) {
if (this.data.openVideoPop) {
wx.pageScrollTo({
scrollTop: that.data.videoScrollNum,// 固定页面滚动距离(即达到禁止滚动的效果)
duration: 300
});
} else {
// 存页面距离
this.setData({
videoScrollNum:e.scrollTop
});
}
}
备注
我尝试过在遮罩打开的时候为页面容器添加hiddenScroll这个class,然后遮罩关闭后再移除的方法,虽然的确可以禁止滚动,但当弹出层出现,底层body会回到页面顶部,这个并不是我想要的,所以此方法被放弃了。
.hiddenScroll{
height:100%;
overflow:hidden;
}
swiper组件的指示点样式修改
- 简单修改:每个小点都有一个class
wx-swiper-dot
。 - 禁用swiper的indicator-dots属性,用view组件模拟dots。
查看参考文章
wx.navigateBack携带参数
场景
在页面A有品牌列表选项(只展示前8个),用户可多选。通过『更多』按钮前往全部品牌列表页B,并携带用户已选项,用户在这个页面可增删选多个品牌,点击『确定』按钮后回到页面A。
期望达到的顺序:
前往顺序:index -> A -> B。
回退顺序:index <- A <- B。
所以B到A页面,不能使用wx.navigateTo
(将把A页面再次加到页面栈,即index -> A -> B -> A,则返回也将是ABAindex)。所以我使用了wx.navigateBack
(传送门):
var brandIds = '111';
var pages = getCurrentPages();// 当前页面
var prevPage = pages[pages.length - 2];// 上一页面
prevPage.setData({// 直接给上一页面赋值
from:'brandFilter',
brandFilterIds:brandIds
}, function() {
wx.navigateBack({ // 返回
delta: 1
});
});
再回到上一页的js,在data里定义from、brandFilterIds,然后在onshow里处理:
if (this.data.from === 'brandFilter') {
this.initData();
this.setData({
from:''
});
}
查看更多介绍
小程序之webview在ios下访问不到
问题描述
ios端小程序里用web-view打开的H5页面有的白屏,H5地址是后台反的。
解决
经过排查问题发现,web-view的src中携带的参数中含有符号"|",所以只能让后台给参数值转码了,h5页面提取参数的时候再解码一下即可。(貌似中文也有这个问题,也需要转码)
如地址http://caiyichen.me?sell_params=shoppe_source:shoppe|show_id:7044
,需要将sell_params值转码。
- 编码
encodeURIComponent()
- 解码
decodeURIComponent()
web-view 组件是一个可以用来承载网页的容器。(web-view传送门)
pointer-events
-webkit-overflow-scrolling
相关文章
iOS safari 如何阻止“橡皮筋效果”【需了解】
微信里面防止下拉"露底"组件 【需了解】
video封面poster
使用的poster属性,开发工具上图片闪一下就没了。在video里用cover-view和cover-image,开发工具里正常显示,但是图片不能自适应。
video层级太高,顶部导航固定上滑会出现,覆盖现象暂无法解决。所以这次没有做tab分类的吸顶功能(也由于顶部内容显示/隐藏条件判断多,无法设置固定滚动距离再吸顶)。