小程序下绘制序列祯,没有H5那么简单和便利。目前小程序的画布推出了
2D
,可以提高画布的渲染效率和内存的消耗。实际上用起来却没那么好用。本文仍然是以传统的小程序画布的方式去实现。
- 通过
wx.downloadFile
方法下载网络图片,转为本地的临时文件tempfilepath
。 - 一次性加载全部的序列祯,然后清除,防止播放序列祯出现闪屏。
- 通过定时器播放序列祯。
wxml的代码
创建普通的画布,注意不是
2d
的即刻。还是传统的画布api
。
<!--index.wxml-->
<view class="container">
<canvas
style="width:{{config.width}}px;height:{{config.height}}px;position:absolute;top:0px;left:0px;"
canvas-id="firstCanvas"
disable-scroll="true"
bindtouchstart="canvasStart"
bindtouchmove="canvasMove"
bindtouchend="canvasEnd"
touchcancel="canvasEnd"
binderror="canvasIdErrorCallback"
></canvas>
</view>
JS画布的逻辑实现
这边先把代码全部都贴出来,再分步解释。
// 画布绘制序列帧
const store = getApp().store;
const create = getApp().create;
const regeneratorRuntime = getApp().regeneratorRuntime;
create(store, {
data: {
config: {
width: 375,
height: 375,
}
},
onLoad() {
const result = wx.getSystemInfoSync();
if (result) {
const config = {
width: result.windowWidth,
height: result.windowHeight,
}
this.setData({ config })
}
this.createDownLoadList();
},
begainAnimate(params) {
const context = wx.createCanvasContext('firstCanvas');
// 第一帧
const width = this.data.config.width;
const height = this.data.config.height;
// 播放序列帧会出现闪屏。
// 猜测可能是画布初始化的时候,就没有图片资源。
// 所以用了一个很粗暴的方法
// 在刚开始把所有的图片全部都加载到画布里面去。
for (var i = params.length - 1; i >= 0; i--) {
context.drawImage(params[i].tempFilePath, 0, 0, width, height);
}
context.draw();
let index = 0;
// 网上说需要 requestAnimationFrame 来刷新,其实只要控制在 16ms刷一次就可以。刷的频率不能太高。
// setInterval(()=>{
// }, 16)
const timer = setInterval(() => {
index++;
if (index > (params.length - 1)) {
clearInterval(timer);
return;
}
context.clearRect(0, 0, width, height);
context.drawImage(params[index].tempFilePath, 0, 0, width, height);
context.draw();
}, 100)
},
async createDownLoadList() {
const count = 85;
var pathList = [];
for (var i = 0; i < count; i++) {
const name = `00000${i}`.substr(-5);
const imagePath = `https://wx.sephora.cn/h5/flawless/flawless6/img/index/sy2_${name}.jpg`;
pathList.push({
index: i,
imagePath: imagePath
});
}
let loadList = [];
for (var i = 0; i < count; i++) {
loadList.push(this.preLoad(pathList[i]));
}
const fileList = await Promise.all(loadList);
this.begainAnimate(fileList);
},
preLoad(params) {
return new Promise((resolve) => {
wx.downloadFile({
url: params.imagePath,
success(res) {
if (res.statusCode === 200) {
params.tempFilePath = res.tempFilePath
resolve(params);
} else {
console.log('下载图片出错');
}
}
})
})
},
});
小程序骨架使用的是
westore
的创建形式,这边不用太过于在意。首先这边用promise
包了一个下载的方法。通过for
循环,创建出promise
的下载队列出来。然后在await
整个下载的过程回调。从而保证所有的图片都下载完毕,并且都拿到了临时路径。
preLoad(params) {
return new Promise((resolve) => {
wx.downloadFile({
url: params.imagePath,
success(res) {
if (res.statusCode === 200) {
params.tempFilePath = res.tempFilePath
resolve(params);
} else {
console.log('下载图片出错');
}
}
})
})
},
接下来就是播放序列的问题。这边遇到一个很神奇,画布在绘制序列帧的时候,会出现闪烁闪屏。也没找到合适的办法,这边只能粗暴的先把所有的序列祯本地路径全部都绘制到画布上去。然后在清空画布。猜测可能是画布还没有缓存到序列祯的资源,从而导致的闪屏。
for (var i = params.length - 1; i >= 0; i--) {
context.drawImage(params[i].tempFilePath, 0, 0, width, height);
}
context.draw();
最后的步骤就是通过定时器,或者是通过
requestAnimationFrame
去做序列祯的播放都可以。如果是通过定时器的话,需要注意间隔时间不要小于16ms
一下,测试过效果不佳。
const timer = setInterval(() => {
index++;
if (index > (params.length - 1)) {
clearInterval(timer);
return;
}
context.clearRect(0, 0, width, height);
context.drawImage(params[index].tempFilePath, 0, 0, width, height);
context.draw();
}, 100)
网友评论