框架:vue
<template>
<!-- viewBox属性是用于指定用户SVG图像的坐标系统的原点以及尺寸的
不管svg像素多少,都是一个0,0为原点,宽高200个单位的坐标系统,单位与像素无关
宽高100个单位,即坐标系宽高的一半,border是坐标系单位,不是像素单位
-->
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"
:width="width+'rem'" :height="width+'rem'"
>
<circle cx="100" cy="100" :r="100 - border / 2"
fill="none"
opacity="1"
stroke="#fff"
:stroke-width="border"
/>
<circle cx="100" cy="100" :r="100 - border / 2"
fill="none"
transform-origin="50% 50%"
transform="rotate(90)"
:stroke="color"
:stroke-width="border"
:stroke-dasharray="dashLen"
:stroke-dashoffset = "dashOffset"
stroke-linecap="round"
style="transition: stroke-dashoffset 0.4s"
/>
<text x="100" y="100" text-anchor="middle"
fill="#ff6321"
:font-size="45"
font-weight="600" >
{{timeLeft}}{{text}}
</text>
<text x="100" y="140" text-anchor="middle"
:font-size="30" >
{{tips}}
</text>
</svg>
</template>
<script>
export default {
name: 'circlePercent',
props: {
target: {
type: Number,
required: true
},
count: {
type: Number,
required: true
},
width: {
type: Number,
default: 1
},
border: {
type: Number,
default: 28
},
color: {
type: String,
default: '#fcaa55'
},
fontSize: {
type: Number,
default: 30
},
delay: {
type: Number,
default: 2
},
tips:{
type:String,
default:'完成'
},
text:{
type:String,
default:'%'
}
},
data () {
return {
timeLeft: 0,
dashLen: (100 - this.border / 2) * Math.PI * 2
}
},
computed: {
dashOffset () {
return this.dashLen - this.timeLeft / this.count * this.dashLen
}
},
mounted () {
var _this = this
setTimeout(function(){
_this.run()
}, _this.delay)
},
methods:{
run:function() {
this.timeLeft = 0
var _this = this
this.interval = setInterval(function (){
var diff = _this.target / 10
_this.timeLeft += diff < 1 ? 1 : diff
_this.timeLeft = parseInt(_this.timeLeft)
if (_this.timeLeft >= _this.target) {
_this.timeLeft = _this.target
clearInterval(_this.interval)
}
}, 60)
}
}
}
</script>
大致原理:
svg相当于一块画布,可以设置宽高,这里使用
:width="width+'rem'" :height="width+'rem'"
主要为移动设备提供,可以自行修改为px
svg中的viewbox相当于自定义单位,也就是自己的坐标轴,这里viewbox没有px或者rem单位,只是简单的坐标单元格单位,这里设置0,0,200,200表示左上角坐标是0,0,宽高各200个单位,也就是右下角坐标为200,200
进度条部分:
两个circle,一个做进度条的背景色,一个做进度占比的背景色,主要用stroke做环和环上的进度条
stroke表示线段的颜色,也就是那个环
fill表示圆的背景色,stroke-width表示线条的宽度,也就是那个环的厚度
stroke-dasharray和stroke-dashoffset表示画一条虚线,stroke-dasharray表示虚线中的一段线+虚线中的一段间隔长度,设置为进度占比的颜色,stroke-dashoffset表示虚线的间隔的长度,那么dasharry-dashoffset就是虚线中的线段的长度,设计好比例就能实现环形的比例
圆的起始位置不一定是自己想要的,我想从6点钟开始转,于是设置transform:rotate,参数自己设置,
stroke-linecap="round"是进度比的虚线有弧度,不过设置了dasharray和dashoffset就只能看到一段了,看起来像是那唯一的一条线。
style="transition: stroke-dashoffset 0.4s"本意是设置动画,但是不一定生效,iPhone上开启减弱动态效果会使部分动画效果失效,其他手机看情况,所以我自己实现了run函数,用来控制进度
transform rotate是用来旋转带颜色的环的,默认是左上角的顶点开始旋转,默认是x的正方向轴为0度,而我需要进度条从顶点开始运动,所以需要旋转,
transform-origini是设置旋转的中心的,不想从左上角的顶点开始旋转,想从中心旋转就设置transform-origin: "50% 50%"
transform scale可以用来左右翻转scale(-1, 1),或者垂直翻转scale(1, -1),这个跟环的前进方向有关,有时候需要逆时针,有时候需要顺时针
两个text,是在环形进度条中间部分写点东西,也可以自定义
至于函数中的var _this = this,主要是兼容es5,可能有的浏览器不兼容es6语法()=>{}
run函数是控制进度的,每隔60ms更新当前进度达到进度条从0开始跑动的效果
使用:
main.js中注册
Vue.component(circlePercent.name, circlePercent)
其他vue文件中调用
<circlePercent
:count="100"
:target="student.score"
:delay="800"
class="percent1">
</circlePercent>
主要使用了svg画进度条,其他框架或纯html、js可以通用
这个环设置了transform: "rotate(90deg) scale(-1, 1)" transform-origin:"50% 50%"
感兴趣的可以自定义