好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Vue实现圆环进度条的示例

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

查看更多关于Vue实现圆环进度条的示例的详细内容...

  阅读:46次