f21bb0f2ea
Co-authored-by: Cursor <cursoragent@cursor.com>
158 lines
3.8 KiB
Vue
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>
|