长方形底部画线

60 阅读1分钟
<template>
    <div class="outer-container">
        <div class="container" ref="containerRef">
            <div v-for="index in totalRectangles" :key="index - 1" class="rectangle" ref="rectangleRefs"
                :style="{ backgroundColor: (index - 1) % 2 === 0 ? '#1E90FF' : '#FFB6C1' }">
            </div>
            <div v-for="line in lines" :key="line.color" class="line" :style="{
                width: line.width + 'px',
                backgroundColor: line.color,
                left: line.left + 'px'
            }">
                <span class="line-text">{{ line.startIndex }}</span>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch, onUnmounted } from 'vue'

interface Line {
    startIndex: number
    endIndex: number
    color: string
    width: number
    left: number
}

const totalRectangles = ref(30)
const containerRef = ref<HTMLElement | null>(null)
const rectangleRefs = ref<HTMLElement[]>([])
const lines = ref<Line[]>([
    { startIndex: 0, endIndex: 5, color: 'red', width: 0, left: 0 },
    { startIndex: 6, endIndex: 20, color: 'blue', width: 0, left: 0 },
    { startIndex: 21, endIndex: 29, color: 'green', width: 0, left: 0 }
])

const calculateLineWidths = () => {
    if (!containerRef.value || rectangleRefs.value.length === 0) return

    lines.value = lines.value.map(line => {
        const startRect = rectangleRefs.value[line.startIndex]
        const endRect = rectangleRefs.value[line.endIndex]

        if (!startRect || !endRect) return line

        const startPosition = startRect.getBoundingClientRect().left
        const endPosition = endRect.getBoundingClientRect().right
        const containerLeft = containerRef.value!.getBoundingClientRect().left

        return {
            ...line,
            width: endPosition - startPosition,
            left: startPosition - containerLeft
        }
    })
}

const calculateIndex = (arr: number[]) => {
    let len = arr.length
    const res = []
    for (let i = 0; i < len; i++) {
        let startIndex
        let endIndex
        let channelTpye
        if (i === 0) {
            startIndex = 0
            endIndex = arr[i].data.length - 1
            channelTpye = arr[i].channelType
        } else {
            startIndex = arr[i - 1].endIndex + 1
            endIndex = arr[i].data.length - 1 + startIndex
            channelTpye = arr[i].channelType
        }
        res.push({
            startIndex,
            endIndex,
            channelTpye,
            with: 0,
            left: 0
        })
    }
    return res
}

// 监听窗口大小变化
window.addEventListener('resize', calculateLineWidths)

// 在组件挂载后计算线宽度
onMounted(() => {
    calculateLineWidths()
    window.addEventListener('resize', calculateLineWidths)
})

onUnmounted(() => {
    window.removeEventListener('resize', calculateLineWidths)
})

// 监听长方形数量变化
watch(totalRectangles, () => {
    setTimeout(calculateLineWidths, 0)
})
</script>

<style scoped>
.outer-container {
    width: 500px;
    margin: 0 auto;
}

.container {
    display: flex;
    justify-content: space-between;
    padding: 20px;
    position: relative;
    width: 100%;
}

.rectangle {
    width: 8px;
    height: 20px;
}

.line {
    position: absolute;
    bottom: 10px;
    height: 2px;
    transition: all 0.3s ease;
    text-align: center;
}

.line-text {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 10px;
    white-space: nowrap;
    color: #333;
    font-size: 12px;
}
</style>