自学内容网 自学内容网

vue+svg圆形进度条组件

一、实现思路

使用svg的circle元素画两个圆形,一个圆形控制进度,一个绘制底色

二、ProgressCircle.vue

代码示例:

<template>
  <!-- 圆形进度条控件 -->
  <div :class="['progress-circle', `p-circle${randomNumber}`]">
    <svg :width="diameter" :height="diameter">
      <circle
        class="progress-background"
        :r="radius"
        :cy="center"
        :cx="center"
        :stroke-width="strokeWidth"
        :stroke="color.notOccupied"
        fill="none"
      />
      <circle
        class="progress-line"
        :r="radius"
        :cy="center"
        :cx="center"
        :stroke-width="strokeWidth"
        :stroke="color.occupy"
        stroke-linejoin="round"
        stroke-linecap="round"
        fill="none"
        :stroke-dasharray="dashArray"
        :stroke-dashoffset="dashOffset"
      />
    </svg>
    <div class="progress-container">
      <slot></slot>
    </div>
  </div>
</template>

<script>
import { randomString } from '@/utils/index';
export default {
  props: {
    strokeWidth: { type: Number, default: 10, validator: value => value > 0 }, //线条宽度
    color: { type: Object, default: () => ({ occupy: '#1593ff', notOccupied: '#e0e0e0' }) }, //占比颜色
    percentage: { type: Number, required: true, validator: value => value >= 0 && value <= 100 }, //百分比1-100
    basisState: { type: String, default: 'width', validator: value => ['width', 'height'].includes(value) } // 默认以父元素宽度为直径长
  },
  data() {
    return {
      parentSize: 0,
      updateTimer: null,
      randomNumber: null
    };
  },
  computed: {
    // 直径长度
    diameter() {
      return this.parentSize >= this.strokeWidth ? this.parentSize : this.strokeWidth;
    },
    // 半径
    radius() {
      return (this.diameter - this.strokeWidth) / 2; // 减去 stroke-width 的一半,以确保圆环在 SVG 内部完全可见
    },
    // 圆心
    center() {
      return this.diameter / 2;
    },
    // 周长 2πr
    circumference() {
      return 2 * Math.PI * this.radius;
    },
    // 虚线样式,间隔为一个周长
    dashArray() {
      return this.circumference;
    },
    // 虚线与路径起点之间的偏移量(周长的剩余占比)
    dashOffset() {
      return this.circumference - (this.circumference * this.percentage) / 100;
    }
  },
  created() {
    this.randomNumber = randomString(10); //生成随机字符串作为类名,确保多个组件存在时不会冲突
  },
  methods: {
    updateParentSize() {
      this.$nextTick(() => {
        this.updateTimer && clearTimeout(this.updateTimer);
        this.updateTimer = setTimeout(() => {
          const child = document.querySelector(`.p-circle${this.randomNumber}`);
          const parent = child.parentNode;
          this.parentSize = this.basisState == 'width' ? parent.offsetWidth : parent.offsetHeight; // 圆环大小以父元素宽度或高度作为直径
        }, 300);
      });
    }
  },
  mounted() {
    this.updateParentSize();
    window.addEventListener('resize', this.updateParentSize); // 监听窗口大小变化
  },
  beforeDestroy() {
    this.updateTimer && clearTimeout(this.updateTimer);
    window.removeEventListener('resize', this.updateParentSize);
  }
};
</script>

<style lang="scss" scoped>
.progress-circle {
  position: relative;
  .progress-container {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
  }
}
.progress-background {
  transform: rotate(-90deg);
  // 默认情况下,SVG的圆弧是从3点钟方向(即右侧)开始绘制的
  // 通过旋转-90度,可以将起始位置调整到12点钟方向(即顶部)
  transform-origin: 50% 50%;
}
.progress-line {
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
}
</style>

三、父组件使用

<template>
  <div class="head-progress">
    <ProgressCircle :percentage="Number(extraParams.confirmRate || 0)">
      <div class="head_cont">
        <span class="he_text">开票进度</span>
        <span class="he_prec">{{ extraParams.confirmRate || '0.00' }}%</span>
      </div>
    </ProgressCircle>
  </div>
</template>

<script>
export default {
  components: {
    ProgressCircle: () => import('@/components/svgGraphic/progressCircle.vue')
  }
};
</script>

<style lang="scss" scoped>
.head-progress {
  width: 100px;
  height: 100px;
  margin-right: 30px;
  .head_cont {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    .he_text {
      font-size: 14px;
      color: #7180b0;
    }
    .he_prec {
      font-weight: 600;
      font-size: 16px;
      color: #0e1119;
      line-height: 28px;
    }
  }
}
</style>

四、实现效果

在这里插入图片描述


原文地址:https://blog.csdn.net/m0_52228571/article/details/143788237

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!