利用canvas制作进度条实践

版权声明:本文为博主原创文章,若转载,请注明出处及作者,谢谢! https://blog.csdn.net/qq_38047742/article/details/83302720

开门见字

之前写过一篇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模拟了,开销也就只能开销了。

感谢大家费时欣赏!欢迎光临→→个人空间

猜你喜欢

转载自blog.csdn.net/qq_38047742/article/details/83302720