Vue实现圆环进度条的示例


Posted in Vue.js onFebruary 06, 2021

数据展示,一直是各行各业乐此不疲的需求,具体到前端开发行业,则是各种各种图表数据展示,各种表格数据展示,烦不胜烦(繁不胜繁)!
前几天刚做了折线图、柱状图、饼状图之类的图表数据展示效果,今天又碰到了类似圆环进度条的展示效果。天天跟数据打交道,天天跟接口打交道,项目做了不少,菜逼还是菜逼,都是泪啊!
其实说白了,是自己对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 实现圆环进度条的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
vue使用element-ui实现表单验证
Dec 13 Vue.js
vue下拉刷新组件的开发及slot的使用详解
Dec 23 Vue.js
vue 使用rules对表单字段进行校验的步骤
Dec 25 Vue.js
在vue项目中封装echarts的步骤
Dec 25 Vue.js
vue组件是如何解析及渲染的?
Jan 13 Vue.js
vue项目配置 webpack-obfuscator 进行代码加密混淆的实现
Feb 26 Vue.js
Vue通过懒加载提升页面响应速度
May 10 Vue.js
如何理解Vue简单状态管理之store模式
May 15 Vue.js
vue使用节流函数的踩坑实例指南
May 20 Vue.js
vite+vue3.0+ts+element-plus快速搭建项目的实现
Jun 24 Vue.js
详解Vue的列表渲染
Nov 20 Vue.js
vue选项卡切换的实现案例
Apr 11 Vue.js
vue浏览器返回监听的具体步骤
Feb 03 #Vue.js
vue实现禁止浏览器记住密码功能的示例代码
Feb 03 #Vue.js
学习 Vue.js 遇到的那些坑
Feb 02 #Vue.js
Vue常用API、高级API的相关总结
Feb 02 #Vue.js
Vue项目打包部署到apache服务器的方法步骤
Feb 01 #Vue.js
如何在vue中使用video.js播放m3u8格式的视频
Feb 01 #Vue.js
Vue 实现可视化拖拽页面编辑器
Feb 01 #Vue.js
You might like
php多重接口的实现方法
2015/06/20 PHP
Yii的Srbac插件用法详解
2016/07/14 PHP
基于Laravel(5.4版本)的基本增删改查操作方法
2019/10/11 PHP
文本框水印提示效果的简单实现代码
2014/02/22 Javascript
使用console进行性能测试
2015/04/27 Javascript
JS+CSS实现美化的下拉列表框效果
2015/08/11 Javascript
JavaScript实现标题栏文字轮播效果代码
2015/10/24 Javascript
js实现String.Fomat的实例代码
2016/09/02 Javascript
jQuery操作复选框(CheckBox)的取值赋值实现代码
2017/01/10 Javascript
Map.vue基于百度地图组件重构笔记分享
2017/04/17 Javascript
浅谈事件冒泡、事件委托、jQuery元素节点操作、滚轮事件与函数节流
2017/07/22 jQuery
vue-cli开发时,关于ajax跨域的解决方法(推荐)
2018/02/03 Javascript
Vue 自定义动态组件实例详解
2018/03/28 Javascript
Vue render深入开发讲解
2018/04/13 Javascript
vue2实现搜索结果中的搜索关键字高亮的代码
2018/08/29 Javascript
搭建一个nodejs脚手架的方法步骤
2019/06/28 NodeJs
微信小程序实现自定义动画弹框/提示框的方法实例
2020/11/06 Javascript
[06:07]刀塔密之二:攻之吾命受之吾幸
2014/07/03 DOTA
[01:18]PWL开团时刻DAY10——一拳超人
2020/11/11 DOTA
python爬虫实战之最简单的网页爬虫教程
2017/08/13 Python
解决Scrapy安装错误:Microsoft Visual C++ 14.0 is required...
2017/10/01 Python
python操作excel的包(openpyxl、xlsxwriter)
2018/06/11 Python
使用python实现抓取腾讯视频所有电影的爬虫
2019/04/15 Python
python实现二分类的卡方分箱示例
2019/11/22 Python
PyQt5中多线程模块QThread使用方法的实现
2020/01/31 Python
Application Cache未缓存文件无法访问无法加载问题
2014/05/31 HTML / CSS
WebSphere面试题:在WebSphere里面如何部署一个应用
2015/08/02 面试题
教育系毕业生中文求职信范文
2013/10/06 职场文书
如何写好优秀的创业计划书
2014/01/30 职场文书
学生会干部自荐信
2014/02/04 职场文书
销售团队获奖感言
2014/08/14 职场文书
2014幼儿园家长工作总结
2014/11/10 职场文书
2015年毕业实习工作总结
2014/12/12 职场文书
2016党性教育学习心得体会
2016/01/21 职场文书
2019年员工晋升管理制度范本!
2019/07/08 职场文书
关于k8s环境部署mysql主从的问题
2022/03/13 MySQL