
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

// =====================
// 响应式数据
// =====================
const resizableElement = ref(null)  // 元素引用
const width = ref(240)              // 显示的宽度值
const isDragging = ref(false)       // 拖拽状态标识
const startX = ref(0)               // 拖拽起始X坐标
const startWidth = ref(0)           // 拖拽起始宽度
let rafId = null                    // requestAnimationFrame ID

// =====================
// 核心方法
// =====================
const startDrag = (e) => {
    isDragging.value = true

    // 获取初始坐标（同时支持鼠标和触摸事件）
    const clientX = e.clientX ?? e.touches[0].clientX
    startX.value = clientX
    startWidth.value = width.value

    // 添加事件监听（使用 passive 提升滚动性能）
    document.addEventListener('mousemove', handleDrag, { passive: true })
    document.addEventListener('touchmove', handleDrag, { passive: true })
    document.addEventListener('mouseup', stopDrag)
    document.addEventListener('touchend', stopDrag)
}

const handleDrag = (e) => {
    if (!isDragging.value) return

    // 使用 requestAnimationFrame 进行节流
    cancelAnimationFrame(rafId)
    rafId = requestAnimationFrame(() => {
        // 获取当前坐标（兼容触摸事件）
        const clientX = e.clientX ?? e.touches?.[0]?.clientX
        const deltaX = clientX - startX.value
        const newWidth = startWidth.value + deltaX

        // 应用约束（示例最小100px，可根据需要扩展）
        const clampedWidth = Math.max(100, newWidth)

        // 优化：直接操作 CSS 变量减少响应式更新
        resizableElement.value.style.setProperty('--width', `${clampedWidth}px`)

        // 低频更新响应式数据（用于显示数值）
        width.value = clampedWidth
    })
}

const stopDrag = () => {
    isDragging.value = false

    // 清理事件监听
    document.removeEventListener('mousemove', handleDrag)
    document.removeEventListener('touchmove', handleDrag)
    document.removeEventListener('mouseup', stopDrag)
    document.removeEventListener('touchend', stopDrag)
}

// =====================
// 生命周期
// =====================
onMounted(() => {
    // 初始化 CSS 变量
    resizableElement.value.style.setProperty('--width', `${width.value}px`)
})

onBeforeUnmount(() => {
    // 组件卸载时取消未执行的动画帧
    cancelAnimationFrame(rafId)
})
</script>

<template>
    <div class="resizable-element" :style="{ '--width': width + 'px' }" ref="resizableElement">
        <slot/>
        <!-- 拖拽手柄（支持触摸事件） -->
        <div class="dargContainer">
            <div class="dargBar" @mousedown="startDrag" @touchstart.passive="startDrag"/>
        </div>
    </div>
</template>

<style scoped>

.resizable-element {
    --width: 300px;  /* 默认值，会被 JS 覆盖 */
    position: relative;
    height: 100%;
    background: #f8f9fa;
    width: var(--width);
    transition: width 0.15s ease; /* 平滑过渡效果 */
    will-change: width; /* 提示浏览器优化重绘 */
}
.dargContainer{
    position: absolute;
    width: 6px;
    //background: red;
    height: calc(100% - 10px);
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto 0;
}
.dargBar {
    position: relative;
    margin: 0 auto;
    width: 2px;
    height: 100%;
    cursor: col-resize;
    border-radius: 2px;
    opacity: 0;
    background: #00000000;
    transition: opacity 0.1s ease, background 0.1s ease;
    transform: translateZ(0); /* 触发 GPU 加速 */
    z-index: 1;
}

/* 悬停状态 */
.dargBar:hover, .dargContainer:hover .dargBar{
    opacity: 1;
    background: #495057cc;
}

/* 拖拽激活状态 */
.dargBar:active {
    background: #212529;
}

/* 移动端优化 */
@media (hover: none) {
    .dargBar {
        opacity: 0.5;  /* 移动端保持可见 */
        width: 12px;   /* 增大触摸区域 */
    }
}
</style>
