canvas之进度条
效果:

封装的组件
<template>
    <div class="circle" :style="{ width: props.radius + 'px', height: props.radius + 'px' }">
        <div class="circle-bg" :style="{ width: props.radius - 5 + 'px', height: props.radius - 5 + 'px', borderWidth: props.lineWidth + 'px', borderColor: props.borderColor }"></div>
        <canvas :id="circleProgressId" class="circle-progress"></canvas>
    </div>
</template>
<script lang="ts" setup>
import { uniqueId } from 'lodash';
const props = withDefaults(
    defineProps<{
        radius?: number; // 半径
        color?: string[]; // 渐变颜色
        progress: number; // 进度
        lineWidth?: number; // 线宽
    }>(),
    {
        radius: 35,
        color: () => ['rgb(72, 157, 125)', 'rgb(52, 254, 125)'],
        progress: 50,
        lineWidth: 16,
        borderColor: 'rgba(0, 150, 255, 1)',
    }
);
// 随机表格id
const circleProgressId: string = uniqueId('circleProgress_');
watch(
    () => props.progress,
    () => {
        nextTick(() => {
            draw();
        });
    },
    {
        deep: true,
        immediate: true,
    }
);
let circleLoading: any = null;
const draw = () => {
    circleLoading && clearInterval(circleLoading);
    let process = 0.0; // 进度
    const canvas: any = document.getElementById(circleProgressId);
    if (!canvas) {
        setTimeout(draw, 200);
        return;
    }
    const ctx = canvas.getContext('2d');
    const percent = props.progress; // 最终百分比
    const circleX = canvas.width / 2; // 中心x坐标
    const circleY = canvas.height / 2; // 中心y坐标
    const radius = props.radius / 2; // 圆环半径
    const lineWidth = props.lineWidth; // 圆形线条的宽度
    // const fontSize = 50; // 字体大小
    circleLoading = setInterval(() => {
        loading();
    }, 33);
    // 画圆
    function circle(cx: any, cy: any, r: any) {
        ctx.beginPath();
        ctx.moveTo(cx + r, cy);
        ctx.lineWidth = lineWidth;
        ctx.strokeStyle = 'transparent';
        ctx.arc(cx, cy, r, 0, Math.PI * 2);
        ctx.closePath();
        ctx.stroke();
    }
    // 画弧线
    function sector(cx: any, cy: any, r: any, progress: number) {
        ctx.beginPath();
        ctx.moveTo(cx, cy - r);
        ctx.lineWidth = lineWidth;
        // 渐变色 - 可自定义
        const linGrad = ctx.createLinearGradient(circleX, circleY + radius + lineWidth, circleX, circleY - radius - lineWidth);
        linGrad.addColorStop(0.0, props.color[1]);
        linGrad.addColorStop(1.0, props.color[0]);
        // linGrad.addColorStop(0.5, '#9bc4eb');
        ctx.strokeStyle = linGrad;
        const startAngle = (Math.PI * 3) / 2;
        ctx.arc(cx, cy, r, startAngle, startAngle + Math.PI * 2 * progress);
        ctx.stroke();
    }
    // 刷新
    function loading() {
        // 清除canvas内容
        ctx.clearRect(0, 0, circleX * 2, circleY * 2);
        // 中间的字
        // ctx.font = fontSize + 'px April';
        // ctx.textAlign = 'center';
        // ctx.textBaseline = 'middle';
        // ctx.fillStyle = '#999';
        // ctx.fillText(parseFloat(process).toFixed(0) + '%', circleX, circleY);
        // 圆形
        circle(circleX, circleY, radius);
        // 圆弧
        process > 0 && sector(circleX, circleY, radius, process / 100);
        // 画到传入百分比后停止
        if (process === percent) {
            clearInterval(circleLoading);
            return;
        }
        // 控制结束时动画的速度
        if (process / percent > 0.9) {
            process += 0.8;
        } else if (process / percent > 0.8) {
            process += 1.05;
        } else if (process / percent > 0.7) {
            process += 1.25;
        } else {
            process += 1.5;
        }
        // 超出时用传入百分比
        if (process > percent) {
            process = percent;
        }
    }
};
</script>
<style lang="scss" scoped>
.circle {
    width: 100%;
    height: 100%;
    position: relative;
    .circle-bg {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        border: 8px solid rgba(42, 113, 88, 0.2); /* 圆环的颜色 */
        border-radius: 50%; /* 设置为50%表示绘制圆形 */
    }
    .circle-progress {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%) scale(-1, 1) !important;
    }
}
</style>
 
使用方式
<CircleProgress
    :radius="60"
    borderColor="rgba(0, 150, 255, 1)"
    :progress="75"
    :color="['#0096FF', '#0096FF']"
    :lineWidth="3"
/>
                









![[bug]java导出csv用Microsoft Office Excel打开乱码解决](https://img-blog.csdnimg.cn/c071273d81c94b22a0d3048d9a9f36dc.png)








