数据展示,一直是各行各业乐此不疲的需求,具体到前端开发行业,则是各种各种图表数据展示,各种表格数据展示,烦不胜烦(繁不胜繁)!
前几天刚做了折线图、柱状图、饼状图之类的图表数据展示效果,今天又碰到了类似圆环进度条的展示效果。天天跟数据打交道,天天跟接口打交道,项目做了不少,菜逼还是菜逼,都是泪啊!
其实说白了,是自己对canvas不熟,对CSS3不熟,所以就找了一个现成的轮子:
<template>
<div class= "content" ref= "box" >
<svg style= "transform: rotate(-90deg)" :width= "width" :height= "width" xmlns= "http://www.w3.org/2000/svg" >
<circle :r= "(width-radius)/2"
:cy= "width/2"
:cx= "width/2"
:stroke-width= "radius"
:stroke= "backgroundColor"
fill= "none"
/>
<circle ref= "$bar"
:r= "(width-radius)/2"
:cy= "width/2"
:cx= "width/2"
:stroke= "barColor"
:stroke-width= "radius"
:stroke-linecap= "isRound ? 'round' : 'square'"
:stroke-dasharray= "(width-radius)*3.14"
:stroke-dashoffset= "isAnimation ? (width-radius) * 3.14 : (width - radius) * 3.14 * (100 - progress) / 100"
fill= "none"
/>
</svg>
<div class= "center_text" :style= "{color, fontSize}" >
<p v- if = "!$slots.default" class= "title" >{{progress}}%</p>
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
radius: {
type: [Number, String],
default : 20
}, // 进度条厚度
progress: {
type: [Number, String],
default : 20
}, // 进度条百分比
barColor: {
type: String,
default : "#1890ff"
}, // 进度条颜色
backgroundColor: {
type: String,
default : "rgba(0,0,0,0.3)"
}, // 背景颜色
isAnimation: {
// 是否是动画效果
type: Boolean,
default : true
},
isRound: {
// 是否是圆形画笔
type: Boolean,
default : true
},
id: {
// 组件的id,多组件共存时使用
type: [String, Number],
default : 1
},
duration: {
// 整个动画时长
type: [String, Number],
default : 1000
},
delay: {
// 延迟多久执行
type: [String, Number],
default : 200
},
timeFunction: {
// 动画缓动函数
type: String,
default : "cubic-bezier(0.99, 0.01, 0.22, 0.94)"
},
circleWidth: {
//圆环宽度
type: Number,
default : 100,
},
color: {
//文字颜色
type: String,
default : '#000'
},
fontSize: {
//文字大小
type: String,
default : '18px'
}
},
data() {
return {
width: this .circleWidth,
idStr: `circle_progress_keyframes_${ this .id}`
};
},
beforeDestroy() {
// 清除旧组件的样式标签
document.getElementById( this .idStr) &&
document.getElementById( this .idStr).remove();
window.addEventListener(() => {});
},
mounted() {
let self = this ;
this .setCircleWidth();
this .setAnimation();
// 此处不能使用window.onresize
window.addEventListener(
"resize" ,
debounce( function () {
self.setCircleWidth();
self.setAnimation(self);
}, 300)
);
},
methods: {
setCircleWidth() {
let box = this .$refs.box;
let width = box.clientWidth;
let height = box.clientHeight;
let cW = width > height ? height : width;
this .width = cW;
},
setAnimation() {
let self = this ;
if (self.isAnimation) {
// 重复定义判断
if (document.getElementById(self.idStr)) {
console.warn( "vue-circle-progress should not have same id style" );
document.getElementById(self.idStr).remove();
}
// 生成动画样式文件
let style = document.createElement( "style" );
style.id = self.idStr;
style.type = "text/css" ;
style.innerHTML = `
@keyframes circle_progress_keyframes_name_${self.id} {
from {stroke-dashoffset: ${(self.width - self.radius) * 3.14}px;}
to {stroke-dashoffset: ${((self.width - self.radius) *
3.14 *
(100 - self.progress)) /
100}px;}}
.circle_progress_bar${
self.id
} {animation: circle_progress_keyframes_name_${self.id} ${
self.duration
}ms ${self.delay}ms ${self.timeFunction} forwards;}`;
// 添加新样式文件
document.getElementsByTagName( "head" )[0].appendChild(style);
// 往svg元素中添加动画class
self.$refs.$bar.classList.add(`circle_progress_bar${self.id}`);
}
}
}
};
</script>
<style scoped>
.content {height:100%;display:flex;justify-content:center;align-items: center;}
.center_text {position:absolute;}
</style>
使用方法:
< CircleProgress :id = "'circle1'" :circleWidth = "40" :radius = "7" :progress = "30" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#FF4F4F'" />
< CircleProgress :id = "'circle2'" :circleWidth = "40" :radius = "7" :progress = "50" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#FF902A'" />
< CircleProgress :id = "'circle3'" :circleWidth = "40" :radius = "7" :progress = "89" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#FFDB4F'" />
< CircleProgress :id = "'circle4'" :circleWidth = "40" :radius = "7" :progress = "25" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#B8D87E'" />
使用时需要注意一下,如果你的页面中同时使用了超过两个以上的这种圆环进度条,就需要给每个圆环进度条设置不同的id,否则,所有圆环最终展示的数据都会是最后一个圆环的数据。
代码中有一个防抖动的函数,这里就贴一下这个函数:
function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result
const later = function () {
// 据上一次触发时间间隔
const last = + new Date() - timestamp
// 上次被包装函数被调用时间间隔last小于设定时间间隔wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
本文参考的是npm上的一个圆环进度条的插件 vue-circleprogressbar ,之所以没有在项目中直接安装并使用这个插件,是因为这个插件有点不太符合我们开发的需求,比如这个插件不能设置圆环的宽度,不能设置文字的颜色,不能设置文字的大小,再比如这个插件仅仅为了防抖而依赖了lodash(这个lodash的体积还是很大的)。
至于这个组件在react中的使用,按照react的生命周期,或者react hooks的语法,或者dva模式的语法,稍微改巴改巴就可以使用了,很简单,就不再展开了。
作者:小坏
出处:http://tnnyang.cnblogs.com
以上就是Vue实现圆环进度条的示例的详细内容,更多关于Vue 实现圆环进度条的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/tnnyang/p/11655317.html
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did63978