因为业务需要自己写了个分段式进度条的组件Typescript + vue + vexipUi
整体思路就是先有个外容器,包裹着三个模块,分别为起始日期、进度条和截止日期。
进度条模块:
更据宽度来计算格子的数量,格子的宽度固定,需要监听进度条模块容器的宽度
进度百分比 = (现在时间 - 起始时间)/ (结束时间 - 起始时间)
染色格子的数量 = 总格子数量 *(现在时间 - 起始时间)/ (结束时间 - 起始时间)
算出染色格子数量后渲染颜色,在最后一个染色格子上包裹一个tootip
<template>
<div :class="prefix">
<span :class="`${prefix}__left`">2022-02-01</span>
<div ref="tickWrapper" :class="`${prefix}__container`">
<template v-for="tick in totaltick" :key="tick">
<VTooltip v-if="tick === index">
<template #trigger>
<div :class="`${prefix}__tick-container`">
<div :class="[`${prefix}__tick`, tick === index && `${prefix}__tick--active`]"></div>
</div>
</template>
<span>要提示的内容</span>
</VTooltip>
<div v-else :class="`${prefix}__tick-container`">
<div :class="[`${prefix}__tick`, tick < index && `${prefix}__tick--active`]"></div>
</div>
</template>
</div>
<span :class="`${prefix}__right`">2024-06-31</span>
</div>
</template>
<script setup lang="ts">
const prefix = 'progress'
let resizeObserver: ResizeObserver | null = null
const tickWrapper = ref<HTMLElement>()
const totaltick = ref<number>(0)
const index = ref(0)
const startDate = new Date('2022-02-01')
const endDate = new Date('2024-06-31')
const nowDate = new Date()
const totalDifference = 1 + (endDate.getTime() - startDate.getTime()) / (1000 * 3600 * 24)
const timeDifference = 1 + (nowDate.getTime() - startDate.getTime()) / (1000 * 3600 * 24)
const percentage = timeDifference / totalDifference
let width = 0
onMounted(() => {
if (tickWrapper.value) {
resizeObserver = new ResizeObserver(calculateContentHeight)
resizeObserver.observe(tickWrapper.value)
}
})
function calculateContentHeight() {
width = tickWrapper.value?.offsetWidth ?? 0
totaltick.value = Math.floor(width / 12)
index.value = Math.floor(percentage * totaltick.value)
}
</script>
<style lang="scss" scoped>
.progress {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 40px;
padding: 4px;
background: #0e233c;
border: 1px solid #1c5c82;
opacity: 82%;
&__right {
position: absolute;
right: 0;
width: 13%;
padding: 12px;
text-align: center;
}
&__left {
position: absolute;
left: 0;
width: 13%;
padding: 12px;
text-align: center;
}
&__container {
position: absolute;
display: flex;
width: 73%;
height: 30%;
}
&__tick-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
cursor: pointer;
}
&__tick {
width: 6px;
height: 100%;
margin-right: 6px;
background: #26384b;
opacity: 82%;
&--active {
background: #38baff;
}
}
}
</style>