Files
tianyi_DataV/src/components/ChartProgress.vue
T

158 lines
3.8 KiB
Vue

<template>
<div class="grid-progress-bar" :id="domId">
<div
v-for="(item, index) in totalItems"
:key="index"
class="grid-item"
:class="{ completed: index < completedItems }"
:style="{ backgroundColor: getColor(completedItems, index) }"
></div>
</div>
<div class="tip-text">{{ percent }}%</div>
</template>
<script setup>
import { ref, watchEffect, onMounted, onUnmounted } from "vue";
// 示例数据
const props = defineProps({
domId: {
type: String,
default: "progressBar",
require: true,
},
percent: {
type: Number,
default: 0,
},
totalWidth: {
type: String,
default: "80%",
},
gapWidth: {
type: String,
default: "4px",
},
gridWidth: {
type: String,
default: "6.68px",
},
gridHeight: {
type: String,
default: "21px",
},
color: {
type: String,
default: "#4caf50",
},
bgColor: {
type: String,
default: "#ccc",
},
startColor: {
type: String,
//default: "#21564F",
},
endColor: {
type: String,
//default: "#3BFFBA",
},
});
const totalItems = ref(0);
const completedItems = ref(0);
const cacheContainerWidth = ref(0);
const getColor = (total, index) => {
if (total <= index) {
return props.bgColor;
}
if (!props.startColor || !props.endColor) {
return props.color;
}
const totalSteps = total - 1; // 因为是从0到19,共有20个div
const r1 = parseInt(props.startColor.substring(1, 3), 16);
const g1 = parseInt(props.startColor.substring(3, 5), 16);
const b1 = parseInt(props.startColor.substring(5, 7), 16);
const r2 = parseInt(props.endColor.substring(1, 3), 16);
const g2 = parseInt(props.endColor.substring(3, 5), 16);
const b2 = parseInt(props.endColor.substring(5, 7), 16);
const r = Math.round(r1 + ((r2 - r1) * index) / totalSteps).toString(16);
const g = Math.round(g1 + ((g2 - g1) * index) / totalSteps).toString(16);
const b = Math.round(b1 + ((b2 - b1) * index) / totalSteps).toString(16);
return `#${r.padStart(2, "0")}${g.padStart(2, "0")}${b.padStart(2, "0")}`;
};
// const gradientColors = computed(() => {
// const _completedItems = completedItems.value;
// const colors = [];
// for (let i = 0; i < _completedItems; i++) {
// colors.push(getColor(_completedItems, i));
// }
// return colors;
// });
/////
const getTransNumFromCss = (v) => {
return Number(v.replace("px", ""));
};
const setTotalItems = () => {
const div =
(cacheContainerWidth.value - getTransNumFromCss(props.gapWidth)) /
(getTransNumFromCss(props.gapWidth) + getTransNumFromCss(props.gridWidth));
console.log(cacheContainerWidth.value, totalItems.value, "值==---===");
totalItems.value = Math.floor(div);
completedItems.value = Math.floor((totalItems.value * props.percent) / 100);
};
const setContainerWidth = () => {
const dom = document.getElementById(props.domId);
cacheContainerWidth.value = dom.offsetWidth;
setTotalItems();
};
const resizeHandler = () => {
setContainerWidth();
};
const onResize = () => {
window.addEventListener("resize", resizeHandler);
};
const removeResize = () => {
window.removeEventListener("resize", resizeHandler);
};
onMounted(() => {
resizeHandler();
onResize();
});
onUnmounted(() => {
removeResize();
});
</script>
<style scoped>
.grid-progress-bar {
display: inline-flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: v-bind(gapWidth);
width: v-bind(totalWidth);
}
.grid-item {
width: v-bind(gridWidth); /* 固定宽度 */
height: v-bind(gridHeight); /* 固定高度 */
background-color: v-bind(bgColor);
}
.completed {
background-color: v-bind(color);
}
.tip-text {
display: inline-block;
margin-left: 10px;
font-size: 20px;
height: v-bind(gridHeight);
line-height: v-bind(gridHeight);
}
</style>