svg实现3环进度图,可动态调节进度数值,(vue)

发布于:2025-06-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

在这里插入图片描述

<template>
  <div id="app">
    <svg width="400" height="400" viewBox="0 0 400 400">
      <defs>
        <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
          <feDropShadow dx="0" dy="0" stdDeviation="5" flood-color="rgba(0, 0, 0, 0.5)" />
        </filter>
      </defs>
      <!-- 外层圆环 -->
      <circle cx="200" cy="200" r="180" stroke="lightgray" stroke-width="20" fill="none" />
      <circle
        class="progress-circle"
        cx="200"
        cy="200"
        r="180"
        stroke="red"
        stroke-width="20"
        fill="none"
        :stroke-dasharray="outerCircumference"
        :stroke-dashoffset="outerOffset"
        stroke-linecap="round"
        transform="rotate(-90 200 200)"
        filter="url(#shadow)"
      />
      <!-- 中层圆环 -->
      <circle cx="200" cy="200" r="140" stroke="lightgray" stroke-width="20" fill="none" />
      <circle
        class="progress-circle"
        cx="200"
        cy="200"
        r="140"
        stroke="green"
        stroke-width="20"
        fill="none"
        :stroke-dasharray="middleCircumference"
        :stroke-dashoffset="middleOffset"
        stroke-linecap="round"
        transform="rotate(-90 200 200)"
        filter="url(#shadow)"
      />
      <!-- 内层圆环 -->
      <circle cx="200" cy="200" r="100" stroke="lightgray" stroke-width="20" fill="none" />
      <circle
        class="progress-circle"
        cx="200"
        cy="200"
        r="100"
        stroke="blue"
        stroke-width="20"
        fill="none"
        :stroke-dasharray="innerCircumference"
        :stroke-dashoffset="innerOffset"
        stroke-linecap="round"
        transform="rotate(-90 200 200)"
        filter="url(#shadow)"
      />
    </svg>
    <div>
      <label>外层进度: </label>
      <input
        type="number"
        v-model="outerProgress"
        @input="updateProgress('outer')"
        min="0"
        max="100"
      />
    </div>
    <div>
      <label>中层进度: </label>
      <input
        type="number"
        v-model="middleProgress"
        @input="updateProgress('middle')"
        min="0"
        max="100"
      />
    </div>
    <div>
      <label>内层进度: </label>
      <input
        type="number"
        v-model="innerProgress"
        @input="updateProgress('inner')"
        min="0"
        max="100"
      />
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      outerProgress: 0,
      middleProgress: 0,
      innerProgress: 0,
      outerCircumference: 2 * Math.PI * 180,
      middleCircumference: 2 * Math.PI * 140,
      innerCircumference: 2 * Math.PI * 100
    }
  },
  computed: {
    outerOffset() {
      return this.outerCircumference - (this.outerProgress / 100) * this.outerCircumference
    },
    middleOffset() {
      return this.middleCircumference - (this.middleProgress / 100) * this.middleCircumference
    },
    innerOffset() {
      return this.innerCircumference - (this.innerProgress / 100) * this.innerCircumference
    }
  },
  methods: {
    updateProgress(type) {
      if (type === "outer" && this.outerProgress >= 0 && this.outerProgress <= 100) {
        this.outerProgress = this.outerProgress
      } else if (type === "middle" && this.middleProgress >= 0 && this.middleProgress <= 100) {
        this.middleProgress = this.middleProgress
      } else if (type === "inner" && this.innerProgress >= 0 && this.innerProgress <= 100) {
        this.innerProgress = this.innerProgress
      }
    }
  }
}
</script>

<style scoped>
#app {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}
input {
  margin-top: 10px;
  width: 60px;
  text-align: center;
}
.progress-circle {
  transition: stroke-dashoffset 0.5s ease;
}
</style>