Vue3 实现圆环进度条功能

2,391 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

概述

大屏开发中有很多类型进度条功能,今天我们就用 Vue3实现一个进度条功能, 我们先来看看实现后的效果:

iShot_2022-06-15_21.38.52.gif

项目初始化

首先我们新建一个项目,执行如下命令

pnpm create vite vue-circleprogress

选择 vue ,回车,等待项目安装完成, cd 进入项目根目录下,接着安装项目需要的依赖包

pnpm install

安装完成后,我们启动项目

pnpm run dev

控制台输出如下内容

vite v2.9.10 dev server running at:

> Local: http://localhost:3000/
> Network: use `--host` to expose

ready in 353ms.

说明项目正常启动了,下面我们接着开发

进度条

我们先删除项目中多余的内容,新建组件文件 src/components/circleProgress.vue, 添加如下内容

<template>
    <div class="progress">

    </div>
</template>
<script setup>
import { ref, toRefs, watch, onMounted } from 'vue'

</script>
<style lang="css" scoped>
.progress {
    display: inline-block;
    position: relative;
    height: 100px;
}
</style>

实现进度条的功能可以使用 canvassvg 等方案,考虑性能方面可以用 svg 来实现,我们这里了用的就是这种方式。

首先我们需要一个 svg

<svg viewBox="0 0 96 96" ref="circleRef"  style="width: 96px; height: 96px;">
    <circle r="40" cx="48" cy="48" fill="none" stroke-miterlimit="20" stroke-width="10" style="stroke-dasharray: 275, 279.602;stroke:#eee;">
    </circle>
    <circle r="40" cx="48" cy="48" fill="none" stroke-miterlimit="20" stroke-width="10" style="stroke-dasharray: 251, 279.602;stroke:#fdd835;">
    </circle>
</svg>

截屏2022-06-15 下午9.24.45.png

这里我们通过控制 svgstroke-dasharray 属性值来达到控制圆环进度的变化

动态变化的属性值通过 props 将进度值传递到组件里面,使用 watch 监听值的变化,这样圆环进度条功能就实现了,下面来看具体的实现过程。

<div class="progress" :style="{width, height}">
    <svg viewBox="0 0 96 96" class="svg-circle-progress" style="width: 96px; height: 96px;">
        <circle r="40" cx="48" cy="48" fill="none" stroke-miterlimit="20" stroke-width="10" class="svg-progress"
            style="stroke-dasharray: 275, 279.602;stroke:#eee;">
        </circle>
        <circle r="40" cx="48" cy="48" fill="none" stroke-miterlimit="20" stroke-width="10"
            class="svg-progress"
            :style="`stroke-dasharray: ${progressValue}, 279.602;stroke:${color};`">
        </circle>
    </svg>
</div>
<script setup>
import { ref, toRefs, watch } from 'vue'

const props = defineProps({
    progress: {
        type: Number,
        default: () => 20
    },
    color: {
        type: String,
        default: () => "#FFAFAF"
    },
    width: {
        type: String,
        default: () => "210px"
    },
    height: {
        type: String,
        default: () => "100px"
    },
})
const { height, width, color, progress } = toRefs(props)
const progressValue = ref((progress.value / 100) * 250)

watch(progress, (newValue) => {
    progressValue.value = (newValue / 100) * 250
})

</script>
<style lang="css" scoped>
.progress {
    display: inline-block;
    position: relative;
    height: 100px;
    text-align: center;
}
.svg-circle-progress {
    position: relative;
    transform: rotate(-90deg);
}
.svg-progress {
    stroke: #2196f3;
    stroke-linecap: round;
    transition: all .3s linear;
}
</style>

圆环进度条的宽高属性,进度值,进度条的颜色我们设置一个默认值,可以自定义,同时优化下进度条的样式。

除了进度条的变化,我们还需要显示进度值,在 svg 后面我们添加如下代码

 <div class="mask">
{{ progress}}%
</div>

同时添加进度值的样式

.mask {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

接着我们在 App.vue 组件中将进度条组件引入,声明一个进度值,并赋值1到100的随机值,放在定时器中,动态变化

<template>
  <div class="">
    <CircleProgress :progress="progress" color="#fdd835"  />
  </div>
</template>
<script setup>
import { ref } from "vue"
import CircleProgress from "./components/circleProgress.vue";

const progress = ref(50)
setInterval(() => {
    progress.value = Math.floor(Math.random()*100+1)
}, 1000);
</script>