开门见字
之前写过一篇H5新标签progress进度条的使用文章,当时觉得研究的还行,但是发现,这个标签在不同浏览器中样式表现是不一致的,如下:
chrome中:,一抹蓝色划过天际;
火狐中:,一片绿色大森林;
IE中:,一群小点排排坐。
够了,完全不着边际的不一致,就这三大家都各有各的想法,不敢想象其他人了,且本人不才,没有研究出CSS修改progress的方法。当然如果不在乎这些差别,也就无所谓了,然而如果遇见一个较真的设计,那你就挠墙,挠墙或者div模拟模拟实现了。
确实,div模拟也可以实现,但是通过不断的修改宽度颜色,这实际上是不断的进行页面的重绘,js最大的开销就是对DOM的操作引发的页面重绘,所以这是有开销的。前天几天用canvas画贪吃蛇,突然灵光乍现,让这条蛇走直线,缩小他的活动范围,不就是进度条了吗?而且canvas本身就是个画布,在它上面画画,开销什么的肯定接受范围的,否则这个标签就不会成为H5的新宠了。
好了,那就来试试吧。
牛刀小试
考虑到通用性,canvas标签应该是被创建出来的,然后还可以消失,这样就需要用JS动态添加;同时,它不应该影响页面结构,也就说,添加不能引起现有页面布局变化,所以,它得是绝对定位的,脱离文档流;还有,它得能自定义,包括插入位置,样式,这才符合多样需求。好了,其他就让canvas画吧,代码贡献,觉得好就拿去用吧。
function createProgress(done, total, {
el = document.body,
width = 200,
height = 10,
color = "green",
colorBg = "#000",
callback = function() {},
} = {}) {
//创建canvas
let __canvas = null,
__pen = null,
__id = null,
__roll = null,
__pace = done / total * width; //画图的进度
if(createProgress.__id) {
//获取缓存
__id = createProgress.__id;
__pen = createProgress.__pen;
__roll = createProgress.__roll;
} else {
//画画准备
__id = "progress-part-DIY" + new Date().getTime();
__canvas = document.createElement("canvas");
__canvas.id = __id;
__canvas.width = width;
__canvas.height = height;
__canvas.style.backgroundColor = colorBg;
__canvas.style.position = "absolute";
el.appendChild(__canvas);
__pen = __canvas.getContext("2d");
__roll = function(color, pace) {
__pen.fillStyle = color;
__pen.fillRect(0, 0, pace, height);
};
//缓存数据
createProgress.__id = __id;
createProgress.__pen = __pen;
createProgress.__roll = __roll;
}
//开始画进度
__roll(color, __pace);
//进度完成,自动停止,激活回调函数
if(done >= total) {
__roll(color, __pace);
//延时完成最后一步处理
setTimeout(() => {
el.removeChild(document.querySelector("#" + __id))
delete createProgress.__id;
}, 100)
callback();
}
}
代码说明:
1. 首先是参数,这里用es6的方法设置了默认参数,如果对样式没有要求的,就是上述默认的宽高和颜色,并且默认是插入到body中的,其中done是已经完成的数,total是总数,这是两个是必须的,用于画进度图的,回调函数也是选填,默认是空函数,可以根据需求,填写进度完成后的回调内容。
2. 接下来就是创建canvas和2d上下文,这里就需要注意了, 因为调用进度是反复轮询的过程,所以这个函数肯定会被反复调用,然而我们不能反复的创建canvas,否则就是一排canvas,不是进度条了,所以我们利用给函数添加属性的方法,做一个记忆函数,如果已经存在了canvas的一套工具了,那就直接读出缓存继续用,否则就新建一套(注意,这里的函数属性是共享的);
3. 一切就绪,那就调用画画的方法,这里我们用矩形画法完成填充:fillRect(0, 0, pace, height);起始就是0开始,长度pace需要计算一下,因为canvas是按宽的比例来画的,所以要把传入的值换算一下,用已完成/总数的比例*宽度,就是目前的宽度,而高度就是整个填充高度。这样每次画画就像进度条一样不断前进起来;
4. 进度到头需要终止,在实际操作代码中肯定是嵌入相应的终止代码,而在这个函数中,为了保证再次调用不出问题,当进度完成后,也要进行相应的清除动作,删除canvas标签,清除函数的id属性,这里做了一个延时,是为了能够看到100%的进度显示。
效果展示
输入一个测试代码,用定时器代替ajax异步
let done = 0,
total = 5900;
setTimeout(function tt() {
done += Math.random() * 1000;
createProgress(done, total, {
el: document.querySelector("div"),
width: 500,
height: 20,
color: "red",
colorBg: "#002567",
callback: function() {
console.log("over了")
},
});
if(done <= total) {
setTimeout(tt, 1000);
}
}, 1000)
最终就是这样的效果:gif图,大家凑合看看吧,技术有待提高。
最后啰嗦
利用canvas画图实现进度条就是这些,不过这和progress标签一样,需要支持H5的浏览器才行,当然现在主流版本应该都行,如果需要兼容古董浏览器,那就只能用div模拟了,开销也就只能开销了。
感谢大家费时欣赏!欢迎光临→→个人空间