在上一节中,学习了怎么利用SVG的和来制作进度条。记得在文章末尾留了一个悬念,说这一节中,要聊聊怎么用Vue来把这个SVG的进度封装成组件。
咱们先不聊Vue怎么把这个封装成组件(我搜索了一下,有现在所这方面组件,而且做得蛮好的,接下来先学习一下)。今天接着聊上一节中的进度条怎么来实现。不过略有不同。不同点来自于网上一位朋友向我提的一个问题。问题是这样的:
用SVG做一个环形的进度条一样的东西,这个很好做(用的 ),但是,我需要再做一个小圆,随着环形慢慢变成一个圆时一直和头部在一起移动(这个不懂)。这个能稍微指点一下我吗?
说实话,我也很好奇!但我想在以前的基础上添加一个,让这个新添加的跟着内圈做位移(旋转),应该是可以的。也正因为出于好奇,给他找了两个Demo(Demo1、Demo2) 。原本应该能满足其需求。但并不是这样,他希望不借用第三方的库。后来回来自己写了一个 Demo。简单的记录一下这个过程。
简单的分析一下
不管是水平的还是圆形的,其都具有三层,比如下图所示:
灰色表示进度条的底层(总共的长度)
红色表示进度条的进度 (已完成长度)
绿色表示起点 (跟随圆点)
在SVG中的话,对应的就是:
水平进度条,灰色和红色是由元素构建,绿色的由构建
圆形进度条由三个构建
知道其中的原委,那就好办的得多了。咱们可以先绘制一个静态的图出来:
这个时候看到的效果如下:
从效果中,可以看出来,现在绿色的圆点都在默认的起点。并没有跟随进度条红色的部分。在SVG中并没有直接的方法或者API来让绿色点保持在红色点的终点。这个时候咱们需要借助CSS的特性来完成。这也离不开一些数学的计算。具体怎么来计算呢?先来看水平进度条。
通过前面的学习,知道使用可以知道其长度。在这个示例中,通过:
document.querySelectorAll('line')[].getTotalLength()// => 170
可以知道整个水平进度条的总长度是,而红色的进度是通过值来控制的,在这个示例中是。有了这两个值,就很好的控制绿色的值了。使用CSS的来做对应的位移,其位移的值是,即。
在行内添加了,当然你也可以在CSS样式中写。这个时候你看到的效果如下:
上面完成了水平进度条的效果,接下来看圆形进度条。对于圆形的进度条,我们同要要知道其长度,同样可以能过来获取:
document.querySelectorAll('circle')[2].getTotalLength();// =>464.2044677734375
建议上向上取整,此时我们的周长是。除此之外,还可以通过来计算。
因为圆形进度条是一个圆,那么通过是无法实现的,这个时候,需要使用的是中的来旋转。既然需要旋转就需要一个角度值。那又得数学公式了。简单的回忆一下:
弧度 = 角度 * Math.PI /180=> rad = (π /180) * deg角度 = 弧度 *180/ Math.PI => deg = (rad *180) / π
其实就是角度()和弧度()之间的转换。一个完整的圆的弧度是,所以,,,(约)。以度数表示的角度,把数字乘以便转换成弧度;以弧度表示的角度,乘以便转换成度数。
角所对的弧长是半径的几倍,那么角的大小就是几弧度
平时我们常看到的各种弧度如下:
通过JavaScript可以来这样进行角度和弧度之间的换算:
rad =(Math.PI * deg) /180deg =(rad *180) / Math.PI
下图展示了常见的角度和弧度之间的换算:
回到我们的示例当中来。通过可以获取圆角的长度约为,对应红色圆的值为。那么就能获取到红色进度的弧长为。前面说过,角所对的弧长是半径的几倍,那么角的大小就是几弧度:
65 / 74 = .87rad
另外也可以将换成。根据前面的计算公式,可以计算出来:
大约。那么在元素中添加:
transform:rotate(.8783783783783784rad);transform-origin: 100px120px;
这个时候看到的效果如下:
特别声明:SVG的坐标系统和Web中的坐标系统是不一样的,所以需要对元素做坐标变换,也就有了的设置。
添加动画效果
SVG中改变的值,可以实现线条自画的效果。这并不是什么新东西,也不是复杂的东西。在我们今天的示例当中的关键点是怎么当绿色的点跟着移动。
通过前面的了解,在水平进度条中,需要给一个值,而这个值是:
.getTotalLength() - stroke-dashoffset
对于圆形的稍为复杂一点,其要给传一个值:
(.getTotalLength() - stroke-dashoffset) / r;// => 弧度值
或者:
(.getTotalLength() - stroke-dashoffset) / r *180/ Math.PI;=>角度值
既然知道其中原理,我们就来换成Vue的环境。把红色的绑定一个数据,然后使用来动态修改的值。并且动态修改绿色圆点的位置或者旋转值。比如:
line: stroke-dashoffset = "{}"
circle:stroke-dashoffset = "{}"
对应的Vue代码:
letapp =newVue({ el:'#app', data () {
return{ dashOffsetCircle:400, dashOffsetLine:90, } }, methods: { moveLine:function(e){letcircleLine = document.getElementById('circle')
letlineInnerLen = document.getElementById('lineInner').getTotalLength() circleLine.style.transform="translateX("+ (lineInnerLen - e.target.value) +"px)"}, moveCircle:function(e) {
letcircleInner = document.getElementById('circleInner')
letcircleInnerLen = Math.ceil(document.getElementById('circleInner').getTotalLength())
letarcLen = circleInnerLen -this.dashOffsetCircle
letrad = arcLen /74circleInner.style.transform="rotate("+ rad +"rad)"} }})
Vue代码写得比较拙逼,路过的大婶请多多指点。这个时候,你拖动,改变其值时,就可以看到对应的效果。
事实上除了使用元素和元素之外,还可以使用元素来实现类似的效果。感兴趣的同学,不仿使用来做一个。如果做了,记得在下面的评论中与一起分享您的成果。
总结
这篇文章主要在上一节的基础上添加了一个网友想要的效果。就是在进度条上有一个圆点,能跟随进度条一起移动。其实现原理并不复杂。对于水平进度条,通过来改变其位移的位置,对于圆形进度条,则通过旋转来改变其位置。不管是哪一种,都需要动态的计算出他们的值,然后修改对应元素的样式。很多时候CSS和SVG的结合能让我们做出一些意想不到的效果。如果你感兴趣的话,不仿一试。
领取专属 10元无门槛券
私享最新 技术干货