vue组件封装 —— 仪表盘(有缺口的环形进度条内显示百分比值)
组件 s-progress.vue
<template><divclass="el-progress":class="['el-progress--' + type,status ? 'is-' + status : '',{'el-progress--without-text': !showText,'el-progress--text-inside': textInside,},]"role="progressbar":aria-valuenow="percentage"aria-valuemin="0"aria-valuemax="100"><div class="el-progress-bar" v-if="type === 'line'"><divclass="el-progress-bar__outer":style="{ height: strokeWidth + 'px' }"><div class="el-progress-bar__inner" :style="barStyle"><div:style="textStyle"class="el-progress-bar__innerText myText"v-if="showText && textInside">{{ content }}div>div>div>div><divclass="el-progress-circle":style="{ height: width + 'px', width: width + 'px' }"v-else><svg viewBox="0 0 100 100"><pathclass="el-progress-circle__track":d="trackPath":stroke="bgColor":stroke-width="relativeStrokeWidth"fill="none":style="trailPathStyle":stroke-linecap="strokeLinecap">path><pathclass="el-progress-circle__path":d="trackPath":stroke="stroke"fill="none":stroke-linecap="strokeLinecap":stroke-width="percentage ? relativeStrokeWidth : 0":style="circlePathStyle">path>svg>div><divclass="el-progress__text myText"v-if="showText && !textInside":style="{ fontSize: progressTextSize + 'px' }"><template v-if="!status" :style="textStyle">{{ content }}template><i v-else :class="iconClass">i>div>div>
template>
<script>
export default {name: "ElProgress",props: {bgColor: {type: String,default: "#e5e9f2",},rate: {type: Number,default: 1,},type: {type: String,default: "line",validator: (val) => ["line", "circle", "dashboard"].indexOf(val) > -1,},percentage: {type: Number,default: 0,required: true,validator: (val) => val >= 0 && val <= 100,},status: {type: String,validator: (val) => ["success", "exception", "warning"].indexOf(val) > -1,},strokeWidth: {type: Number,default: 6,},strokeLinecap: {type: String,default: "round",},textInside: {type: Boolean,default: false,},width: {type: Number,default: 126,},showText: {type: Boolean,default: true,},color: {type: [String, Array, Function],default: "",},format: Function,},computed: {barStyle() {const style = {};style.width = this.percentage + "%";style.backgroundColor = this.getCurrentColor(this.percentage);return style;},relativeStrokeWidth() {return ((this.strokeWidth / this.width) * 100).toFixed(1);},radius() {if (this.type === "circle" || this.type === "dashboard") {return parseInt(50 - parseFloat(this.relativeStrokeWidth) / 2, 10);} else {return 0;}},trackPath() {const radius = this.radius;const isDashboard = this.type === "dashboard";return `M 50 50m 0 ${isDashboard ? "" : "-"}${radius}a ${radius} ${radius} 0 1 1 0 ${isDashboard ? "-" : ""}${radius * 2}a ${radius} ${radius} 0 1 1 0 ${isDashboard ? "" : "-"}${radius * 2}`;},perimeter() {return 2 * Math.PI * this.radius;},strokeDashoffset() {const offset = (-1 * this.perimeter * (1 - this.rate)) / 2;return `${offset}px`;},trailPathStyle() {return {strokeDasharray: `${this.perimeter * this.rate}px, ${this.perimeter}px`,strokeDashoffset: this.strokeDashoffset,};},circlePathStyle() {return {strokeDasharray: `${this.perimeter *this.rate *(this.percentage / 100)}px, ${this.perimeter}px`,strokeDashoffset: this.strokeDashoffset,transition: "stroke-dasharray 0.6s ease 0s, stroke 0.6s ease",};},stroke() {let ret;if (this.color) {ret = this.getCurrentColor(this.percentage);} else {switch (this.status) {case "success":ret = "#13ce66";break;case "exception":ret = "#ff4949";break;case "warning":ret = "#e6a23c";break;default:ret = "#20a0ff";}}return ret;},iconClass() {if (this.status === "warning") {return "el-icon-warning";}if (this.type === "line") {return this.status === "success"? "el-icon-circle-check": "el-icon-circle-close";} else {return this.status === "success" ? "el-icon-check" : "el-icon-close";}},progressTextSize() {return this.type === "line"? 12 + this.strokeWidth * 0.4: this.width * 0.111111 + 2;},content() {if (typeof this.format === "function") {return this.format(this.percentage) || "";} else {return `${this.percentage}%`;}},},methods: {getCurrentColor(percentage) {if (typeof this.color === "function") {return this.color(percentage);} else if (typeof this.color === "string") {return this.color;} else {return this.getLevelColor(percentage);}},getLevelColor(percentage) {const colorArray = this.getColorArray().sort((a, b) => a.percentage - b.percentage);for (let i = 0; i < colorArray.length; i++) {if (colorArray[i].percentage > percentage) {return colorArray[i].color;}}return colorArray[colorArray.length - 1].color;},getColorArray() {const color = this.color;const span = 100 / color.length;return color.map((seriesColor, index) => {if (typeof seriesColor === "string") {return {color: seriesColor,percentage: (index + 1) * span,};}return seriesColor;});},},
};
script>
<style scoped>
.myText {background-image: linear-gradient(135deg, red, blue);-webkit-background-clip: text;color: transparent;
}
style>
使用范例
<template><div class="progressBox"><Sprogresstype="dashboard":width="width":rate="rate":percentage="percentage":bgColor="bgColor":color="colors":stroke-width="strokeWidth":stroke-linecap="strokeLinecap"/><div class="labelBox">{{ label }}div>div>
template>
<script>
import Sprogress from "./s-progress.vue";
export default {components: { Sprogress },data() {return {label: "CPU",width: 100,strokeLinecap: "square",strokeWidth: 10,rate: 0.75,percentage: 90,bgColor: "#42567F",colors: [{ color: "#5090FF", percentage: 20 },{ color: "#5090FF", percentage: 40 },{ color: "#5090FF", percentage: 60 },{ color: "#5090FF", percentage: 80 },{ color: "#5090FF", percentage: 100 },],};},
};
script><style scoped>
::v-deep .myText {font-weight: bolder;font-size: 20px !important;background-image: linear-gradient(0deg, #498dff, #8bb7fe);
}.progressBox {margin: 130px;width: 80px;display: flex;flex-direction: column;align-items: center;
}
.labelBox {background: #4c8fff;width: 50px;height: 30px;line-height: 30px;text-align: center;color: white;border-radius: 15px;margin-top: -20px;
}
style>
相关参数
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
percentage | 百分比(必填) | number | 0-100 | 0 |
type | 进度条类型 | string | line/circle/dashboard | line |
stroke-width | 进度条的宽度,单位 px | number | — | 6 |
text-inside | 进度条显示文字内置在进度条内(只在 type=line 时可用) | boolean | — | false |
status | 进度条当前状态 | string | success/exception/warning | — |
color | 进度条背景色(会覆盖 status 状态颜色) | string/function/array | — | '' |
width | 环形进度条画布宽度(只在 type 为 circle 或 dashboard 时可用) | number | 126 | |
show-text | 是否显示进度条文字内容 | boolean | — | true |
stroke-linecap | circle/dashboard 类型路径两端的形状 | string | butt/round/square | round |
format | 指定进度条文字内容 | function(percentage) | — | — |
rate | 进度条比例 | number | 0-1 | 1 |
bgColor | 进度条背景色 | string | 任意颜色值 | #e5e9f2 |
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!