<template>
  <div class="slider-container" ref="slider-container">
    <div class="slider-track">
      <div
        class="slider-thumb"
        @touchstart="startDrag"
        @touchmove="onDrag"
        @touchend="endDrag"
        ref="slider-thumb"
        :style="{ left: `${thumbLeft}px` }"></div>
    </div>
    <!-- <div class="slider-value">{{ internalValue }}%</div> -->
  </div>
</template>

<script setup>
import { computed, defineModel, onMounted, onUnmounted, ref, useTemplateRef } from 'vue'

const model = defineModel({ default: 50 })
const internalValue = ref(model.value)
const isDragging = ref(false)
const sliderContainer = useTemplateRef('slider-container')
const sliderThumb = useTemplateRef('slider-thumb')
const max = ref(0)
const min = ref(0)
const emit = defineEmits(['onEnd'])
const touchstartPos = ref(0)
const sliderThumbLeft = ref(0)
const sliderContainerLeft = ref(0)
let animationFrameId = null

const thumbLeft = computed(() => {
  return (internalValue.value / 100) * (max.value - min.value)
})

// 初始化滑块位置
const initSlider = () => {
  max.value = sliderContainer.value?.getBoundingClientRect().width
  min.value = sliderThumb.value?.getBoundingClientRect().width
  sliderContainerLeft.value = sliderContainer.value?.getBoundingClientRect().left
}

const startDrag = event => {
  const touch = event.touches[0]
  touchstartPos.value = touch.clientX
  sliderThumbLeft.value = sliderThumb.value?.getBoundingClientRect().left
  isDragging.value = true
  initSlider()
  onDrag(event)
}

const onDrag = event => {
  if (!isDragging.value) return
  const touch = event.touches[0]
  const sliderRect = sliderContainer.value.getBoundingClientRect()
  const maxRange = max.value - min.value

  let offsetX = touch.clientX - touchstartPos.value + sliderThumbLeft.value - sliderContainerLeft.value
  offsetX = Math.max(0, Math.min(offsetX, maxRange))

  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId)
  }
  animationFrameId = requestAnimationFrame(() => {
    model.value = internalValue.value = Math.round((offsetX / (max.value - min.value)) * 100)
  })
}
const endDrag = () => {
  isDragging.value = false
  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId)
  }
  emit('onEnd', internalValue.value)
}

// 监听DOM插入
let visibilityObserver = null
// 监听DOM可见性
const observeVisibility = () => {
  const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        initSlider()
      }
    })
  })

  if (sliderContainer.value) {
    observer.observe(sliderContainer.value)
  }

  return observer
}

onMounted(() => {
  // 启动观察器
  visibilityObserver = observeVisibility()
})

onUnmounted(() => {
  // 清理观察器
  visibilityObserver?.disconnect()
})
</script>

<style scoped>
.slider-container {
  height: 100%;
  width: 100%;
  height: 100%;
  width: 100%;
  position: relative;
  border-radius: 10px;
  background: linear-gradient(93deg, #59c5ff 22.29%, #fff 48.81%, #ffb33a 75.32%);
  cursor: pointer;
}

.slider-track {
  height: 100%;
  width: 100%;
  position: relative;
  cursor: pointer;
}

.slider-thumb {
  position: absolute;
  /* top: 2px; */
  width: 54px;
  height: 54px;
  border-radius: 9px;
  background: #fff;
  flex-shrink: 0;
  box-shadow: 0px 2px 7.7px 0px rgba(48, 16, 16, 0.25);
  /* transform: translateX(-100%); 修改这里，使滑块右边缘对齐百分比位置 */
}

.slider-value {
  margin-top: 10px;
  text-align: center;
  font-size: 14px;
}
</style>
