使用Snap.svg库制作动态下载按钮
由于项目需求,手机端h5页面需要制作一个带圆形进度条的下载按钮,我首先想到的是用canvas来实现,可是经过试验之后,我处理不好在移动端的可恶的毛边,又转战使用css3来实现,css3实现的进度条没有毛边了,可是逻辑却复杂的很,需要分左右两层来实现,项目需求还有不同的下载状态,圆形进度条内部有不同的图标,而且状态转换的过程又有动画,所以就放弃了使用css3。经过一段时间在网上辛苦地寻找解决方案,终于找到了一个合适的,那就是SVG技术。而且有一个现成的库,可以方便快捷的实现动画,svg是矢量图形,同时解决了canvas和css3的痛点。
首先,我们假设按钮的根结点为 <div class="btn">,我们在根结点下加入 <svg class="svg" width="100" height="100" viewbox="0 0 100 100"> 这个标签。
然后,在svg标签里制作圆形图标,代码如下:
<div class="btn"> <svg class="svg" width="100" height="100" viewbox="0 0 100 100"> <circle cx="50" cy="50" r="44" stroke-width="5" stroke="#ededed" fill="none"></circle> <circle cx="50" cy="50" r="44" stroke-width="5" stroke="#FF9000" fill="none" transform="matrix(0,-1,1,0,0,100)" stroke-dasharray="0 276.32"></circle> <circle cx="50" cy="50" r="42" fill="rgba(0,0,0,0.4)"></circle> </svg> </div>
其中前两个circle的边框用来制作进度条,第三个用来制作背景颜色,第一个circle边框做进度条背景颜色,第二个circle表示当前进度的的颜色。原理就是利用stroke-dasharray的偏移量来控制进度条的进度,matrix(0,-1,0,0,100)将偏移量移动到12点的位置(进度为0的位置),然后通过js改变stroke-dasharray的数值就可以动态显示进度。
按钮的初始状态,正在下载状态,暂停状态,下载完成状态,每一个状态都用三条直线来控制,如果某条直线不需要,就将两个点坐标设置为一样(两点决定一条直线),代码如下:
//初始化svg里面的的下载图标状态 var svg = [],l1=[],l2=[],l3=[];//l1,l2,l3表示三条直线 var len = $(".svg").length; for(var i = 0;i < len;i++){ svg[i] = Snap(".themes section:nth-of-type("+(i+1)+") .svg"); l1[i] = svg[i].paper.line(50,25,50,75.7).attr({ stroke:"#fff", strokeWidth:5 }); l2[i] = svg[i].paper.line(30,50,50,75).attr({ stroke:"#fff", strokeWidth:5 }); l3[i] = svg[i].paper.line(70,50,50,75).attr({ stroke:"#fff", strokeWidth:5 }); }
因为项目里有多个下载按钮,所以我用一个数组来维护所有的按钮,将所有的线放入l1,l2,l3三个数组里。
状态转换过程代码:
//下载过程变换动画 function toStopBtn(l1,l2,l3){ l1.animate({ x1:50, y1 : 75.7, x2:50, y2:75.7 },500,function(){ l2.animate({ x1:40, y1:30, x2:40, y2:70 },300); l3.animate({ x1:60, y1:30, x2:60, y2:70 },300); }); }
有好几个状态转换,这里只列举一个,就是通过线段两个点的位置的改变和改变过程所需要的时间来实现转改变化。
svg里面的大小可以用数值来控制(表示多少个px),也可以用百分比来控制,其他的像rem,em没有测试。
在不同的终端可能按钮的大小不同我们可以通过缩放来实现,动态添加style标签,代码:
var html = document.documentElement; var dpr = window.devicePixelRatio; var width = html.getBoundingClientRect().width; var zoomVal = width * 0.3 / 360; var fontSize = width / 10; html.style.fontSize = fontSize + "px"; var head = document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.innerHTML = ".themes .themeWrap .img .btn svg {zoom : "+zoomVal+";}" head.appendChild(style);
其中Snap.svg库的api 是从张鑫旭大神博客里学习的可以看一下http://www.zhangxinxu.com/GitHub/demo-Snap.svg/demo/basic/Element.add.php