news 2026/8/29 13:48:43

Vue3进度条(Progress)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue3进度条(Progress)

Vue2进度条(Progress)

可自定义设置以下属性:

  • 进度条宽度(width),单位 px,类型:string | number,默认 undefined;type: 'line' 时,为进度条宽度,默认值 '100%';type: 'circle' 时,为进度圈宽高,默认值 120

  • 当前进度百分比(percent),类型:number,默认 0

  • 进度条的尺寸(lineSize),单位 px,类型:number,默认 undefined;type: 'line' 时,为进度条线高,默认值 8;type: 'circle' 时,单位是进度圈画布宽度的百分比,默认值 6

  • 进度条的色彩(lineColor),类型:string | {'0%'?: string, '100%'?: string, from?: string, to?: string, direction?: 'left'|'right'},默认 undefined;传入 string 时为纯色,传入 object 时为渐变,进度圈时 direction: 'left' 为逆时针,direction: 'right' 为顺时针

  • 进度条边缘的形状(lineCap),类型:'round' | 'square',默认 'round'

  • 是否显示进度数值或状态图标(showInfo),类型:boolean,默认 true

  • 进度数值或状态图标的尺寸(infoSize),单位 px,类型:number,默认 undefined;type: 'line' 时,默认值 14;type: 'circle' 时,默认值 undefined

  • 进度完成时的信息(success),类型:string | slot,默认 undefined

  • 内容的模板函数(format),类型:(percent: number) => (string | number) | slot,默认:(percent: number) => percent + '%'

  • 进度条类型(type),类型:'line' | 'circle',默认 'line'

效果如下图:

在线预览

①创建进度条组件Progress.vue:

其中引入使用了以下工具函数:

  • 监听插槽存在 useSlotsExist
  • 获取依赖注入 useInject

<script setup lang="ts"> import { computed } from 'vue' import { useSlotsExist, useInject } from 'components/utils' export interface Gradient { '0%'?: string '100%'?: string from?: string to?: string direction?: 'left' | 'right' // 默认 'right' } export interface Props { width?: number | string // 进度条宽度,单位 px;type: 'line' 时,为进度条宽度,默认值 '100%';type: 'circle' 时,为进度圈宽高,默认值 120 percent?: number // 当前进度百分比 lineSize?: number // 进度条的尺寸,单位 px;type: 'line' 时,为进度条线高,默认值 8;type: 'circle' 时,单位是进度圈画布宽度的百分比,默认值 6 lineColor?: string | Gradient // 进度条的色彩,传入 string 时为纯色,传入 Gradient 时为渐变,进度圈时 direction: 'left' 为逆时针,direction: 'right' 为顺时针 lineCap?: 'round' | 'butt' // 进度条边缘的形状 showInfo?: boolean // 是否显示进度数值或状态图标 infoSize?: number // 进度数值或状态图标的尺寸,单位 px;type: 'line' 时,默认值 14;type: 'circle' 时,默认值 24 success?: string // 进度完成时的信息 string | slot format?: (percent: number) => string | number // 内容的模板函数 function | slot type?: 'line' | 'circle' // 进度条类型 } const props = withDefaults(defineProps<Props>(), { width: undefined, percent: 0, lineSize: undefined, lineColor: undefined, lineCap: 'round', showInfo: true, infoSize: undefined, success: undefined, format: (percent: number) => percent + '%', type: 'line' }) const { colorPalettes } = useInject('Progress') // 主题色注入 const slotsExist = useSlotsExist(['success']) // 进度条宽度/进度圈宽高 const progressSize = computed(() => { if (props.width === undefined) { if (props.type === 'line') { return '100%' } if (props.type === 'circle') { return '120px' } } return typeof props.width === 'number' ? `${props.width}px` : props.width }) // 进度条高度;进度圈线宽 const progressLineSize = computed(() => { if (props.lineSize === undefined) { if (props.type === 'line') { return 8 } if (props.type === 'circle') { return 6 } } return props.lineSize as number }) // 进度条/圈进度数值或状态图标尺寸 const progressInfoSize = computed(() => { if (props.infoSize === undefined) { if (props.type === 'line') { return '14px' } if (props.type === 'circle') { return '24px' } } return `${props.infoSize}px` }) // 圆条周长 const perimeter = computed(() => { return (100 - progressLineSize.value) * Math.PI }) // 圆条轨道路径指令 const path = computed(() => { const long = 100 - progressLineSize.value return `M 50,50 m 0,-${long / 2} a ${long / 2},${long / 2} 0 1 1 0,${long} a ${long / 2},${long / 2} 0 1 1 0,-${long}` }) // 是否为渐变色 const isGradientColor = computed(() => { if (props.lineColor !== undefined && typeof props.lineColor !== 'string') { return true } return false }) // 进度条/圈颜色 const lineColorComputed = computed(() => { if (props.lineColor === undefined) { return colorPalettes.value[5] } else if (typeof props.lineColor === 'string') { return props.lineColor } else { return `linear-gradient(to ${props.lineColor.direction || 'right'}, ${props.lineColor['0%'] || props.lineColor.from}, ${props.lineColor['100%'] || props.lineColor.to})` } }) // 进度圈渐变色 id const circleGradient = computed(() => { if (isGradientColor.value) { const gradientColor = props.lineColor as Gradient if (gradientColor.direction === undefined || gradientColor.direction === 'right') { return `right-${gradientColor['0%'] || gradientColor.from}-${gradientColor['100%'] || gradientColor.to}` } return `left-${gradientColor['100%'] || gradientColor.to}-${gradientColor['0%'] || gradientColor.from}` } return null }) const circleColorFrom = computed(() => { if (isGradientColor.value) { const gradientColor = props.lineColor as Gradient if (gradientColor.direction === undefined || gradientColor.direction === 'right') { return gradientColor['0%'] || gradientColor.from } else { return gradientColor['100%'] || gradientColor.to } } return }) const circleColorTo = computed(() => { if (isGradientColor.value) { const gradientColor = props.lineColor as Gradient if (!gradientColor.direction || gradientColor.direction === 'right') { return gradientColor['100%'] || gradientColor.to } else { return gradientColor['0%'] || gradientColor.from } } return }) const showPercent = computed(() => { return props.format(props.percent > 100 ? 100 : props.percent) }) const showSuccess = computed(() => { return slotsExist.success || props.success }) </script> <template> <div v-if="type === 'line'" class="progress-line-wrap" :style="` --progress-size: ${progressSize}; --progress-primary-color: ${lineColorComputed}; --progress-success-color: #52c41a; --progress-font-size: ${progressInfoSize}; --progress-border-radius: ${lineCap === 'round' ? '100px' : 0}; `" > <div class="progress-inner"> <div :class="['progress-bg', { 'line-success': percent >= 100 && !isGradientColor }]" :style="`width: ${percent >= 100 ? 100 : percent}%; height: ${progressLineSize}px;`" ></div> </div> <template v-if="showInfo"> <Transition name="fade" mode="out-in"> <span v-if="percent >= 100" class="progress-success"> <svg v-if="showSuccess === undefined" class="icon-svg" focusable="false" ><script setup lang="ts"> import Progress from './Progress.vue' import { ref } from 'vue' import { MinusOutlined, PlusOutlined } from '@ant-design/icons-vue' import type { ProgressProps } from 'vue-amazing-ui' const percent = ref(80) const lineCapOptions = [ { label: 'round', value: 'round' }, { label: 'butt', value: 'butt' } ] const lineCap = ref<ProgressProps['lineCap']>('butt') function onIncrease(scale: number) { const res = percent.value + scale if (res > 100) { percent.value = 100 } else { percent.value = res } } function onDecline(scale: number) { const res = percent.value - scale if (res < 0) { percent.value = 0 } else { percent.value = res } } </script> <template> <div style="width: 900px"> <h1>{{ $route.name }} {{ $route.meta.title }}</h1> <h2 class="mt30 mb10">基本使用</h2> <Progress :percent="percent" /> <h2 class="mt30 mb10">进度圈</h2> <Space align="center"> <Progress type="circle" :percent="percent" /> <Button @click="onDecline(5)" size="large" :icon="MinusOutlined">Decline</Button> <Button @click="onIncrease(5)" size="large" :icon="PlusOutlined">Increase</Button> </Space> <h2 class="mt30 mb10">完成进度条</h2> <Flex vertical> <Progress :percent="100" /> <Progress type="circle" :percent="100" /> </Flex> <h2 class="mt30">渐变进度条</h2> <h3 class="mb10"> strokeColor: { '0%': '#108ee9', '100%': '#87d068', direction: 'right' } 或 { from: '#108ee9', to: '#87d068', direction: 'right' } </h3> <Flex vertical> <Progress :line-color="{ '0%': '#108ee9', '100%': '#87d068' }" :percent="percent" /> <Space align="center"> <Progress type="circle" :line-color="{ '0%': '#108ee9', '100%': '#87d068' }" :percent="percent" /> <Button @click="onDecline(5)" size="large" :icon="MinusOutlined">Decline</Button> <Button @click="onIncrease(5)" size="large" :icon="PlusOutlined">Increase</Button> </Space> </Flex> <h2 class="mt30 mb10">自定义样式</h2> <Flex vertical> <Progress style="--progress-success-color: #ff6900" :line-size="24" :line-color="{ '0%': '#108ee9', '100%': '#87d068', direction: 'left' }" :info-size="24" :percent="percent" /> <Space align="center"> <Progress style="--progress-success-color: #ff6900" type="circle" :width="180" :line-size="14" :line-color="{ '0%': '#108ee9', '100%': '#87d068', direction: 'left' }" :info-size="28" :percent="percent" /> <Button @click="onDecline(5)" size="large" :icon="MinusOutlined">Decline</Button> <Button @click="onIncrease(5)" size="large" :icon="PlusOutlined">Increase</Button> </Space> </Flex> <h2 class="mt30 mb10">自定义边缘形状</h2> <Flex vertical> <Radio :options="lineCapOptions" v-model:value="lineCap" button button-style="solid" /> <Progress :line-size="20" :line-color="{ '0%': 'white', '100%': 'pink' }" :line-cap="lineCap" :info-size="20" :percent="percent" /> <Space align="center"> <Progress type="circle" :width="160" :line-size="12" :line-color="{ '0%': '#e3f2fd', '100%': '#2080f0' }" :line-cap="lineCap" :info-size="24" :percent="percent" /> <Button @click="onDecline(5)" size="large" :icon="MinusOutlined">Decline</Button> <Button @click="onIncrease(5)" size="large" :icon="PlusOutlined">Increase</Button> </Space> </Flex> <h2 class="mt30 mb10">自定义文字</h2> <Flex vertical> <Progress :line-size="20" :info-size="20" :percent="percent" :format="(percent: number) => `$${percent}`" success="Done" /> <Progress style="--success-color: #d48806" :line-size="20" :info-size="20" :percent="percent"> <template #format="{ percent }"> <span style="color: #d4380d">{{ percent }}%</span> </template> <template #success> <span style="color: #d48806">Bingo</span> </template> </Progress> <Space align="center"> <Progress type="circle" :width="160" :line-size="12" :info-size="24" :percent="percent" :format="(percent: number) => `${percent} Days`" success="Done" /> <Progress style="--success-color: #d48806" type="circle" :width="160" :line-size="12" :info-size="24" :percent="percent" > <template #format="{ percent }"> <span style="color: #d4380d">{{ percent }}%</span> </template> <template #success> <span style="color: #d48806">Bingo</span> </template> </Progress> <Button @click="onDecline(5)" size="large" :icon="MinusOutlined">Decline</Button> <Button @click="onIncrease(5)" size="large" :icon="PlusOutlined">Increase</Button> </Space> </Flex> </div> </template>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 13:45:25

2026年AI论文平台推荐:9款高效AI工具一站式清单

一、AI 全面赋能学术写作 人工智能技术正以惊人的速度渗透到学术研究的各个环节&#xff0c;AI 工具在提升论文写作效率与质量方面展现出巨大潜力。从选题构思、内容撰写&#xff0c;到语言润色和查重检测&#xff0c;AI 实现了全流程的智能化支持。 本文将为您精选 9 款当前市…

作者头像 李华
网站建设 2026/8/29 13:45:23

DSP算法FPGA实现:从理论到硬件的完整工程链路与实践指南

1. 项目概述&#xff1a;从“汇总”到“体系化”的工程实践 “DSP/算法/FPGA实现汇总”这个标题&#xff0c;乍一看像是一个技术列表或者资料合集。但作为一个在信号处理与硬件实现领域摸爬滚打了十多年的工程师&#xff0c;我深知这背后远不止是简单的罗列。它指向的是一个贯穿…

作者头像 李华
网站建设 2026/8/29 13:44:48

mermaid流程图

文章目录数据库er图mermaid编写三国事件其他有一定用处&#xff0c;例如常规流程图&#xff0c;数据库er图等。数据库er图 ai时代更加好做了&#xff0c;例如有数据库建表语句&#xff0c;丢给ai让他生成mermaidER图代码。 比dbeaver灵活&#xff0c;比直接让ai生成er图快速(a…

作者头像 李华
网站建设 2026/8/29 13:44:40

千问本地部署实战:从Ollama到Spring AI的完整接入指南

这段时间&#xff0c;业内关于“苹果和千问合作出现调整”的讨论很多。围绕 iPhone 中国市场的大模型合作&#xff0c;苹果与阿里之间的消息一波接一波&#xff0c;先是传出合作推进&#xff0c;又陆续出现集成层面的调整。很多人只把这件事当成商业新闻看&#xff0c;但作为开…

作者头像 李华
网站建设 2026/8/29 13:42:38

前端工程协作的构建与发布

前端工程协作的构建与发布不少方案在演示环境里显得顺畅&#xff0c;进入多人协作或长期运行后才暴露问题。“前端工程协作的构建与发布”关注的正是这段落差。对页面渲染与用户交互而言&#xff0c;可维护的实现不靠一句“已经处理异常”&#xff0c;而靠清楚的触发条件、可观…

作者头像 李华
网站建设 2026/8/29 13:39:26

IBASE MI1001 Mini-ITX工业主板:边缘计算与工控替换的可靠之选

IBASE这个名字&#xff0c;常在工控圈和嵌入式项目里出现。关注这个牌子的人&#xff0c;要么是在做数字标牌、自助终端&#xff0c;要么就是在给特定行业找能稳定跑五六年的核心板。这次MI1001 Mini-ITX主板的发布&#xff0c;从型号命名和板型定位来看&#xff0c;就是奔着“…

作者头像 李华