You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3+Vite双手柄小时范围滑块组件报错求助

解决Vue3双手柄小时范围滑块拖动报错问题

错误原因

拖动手柄时触发的mousemove事件中,event.target并非你定义的<input type="range">元素,导致event.target.value为undefined,进而访问value[0]抛出Cannot read properties of undefined错误。同时原逻辑混用了原生range输入和手柄拖动的事件处理,导致逻辑冲突。

解决思路与修正代码

1. 核心修正点

  • 拆分事件处理:将原生range输入的处理与手柄拖动的处理分开,避免事件对象混用。
  • 基于鼠标位置计算手柄值:通过滑块容器的宽度和鼠标偏移量,计算手柄对应的百分比与小时值。
  • 确保响应式更新:修改数组时创建新数组,保证Vue能检测到数据变化。
  • 移除冗余的原生range输入(若不需要单滑块控制)。

2. 完整修正代码

模板部分

<template>
  <div class="range-container">
    <div class="range-slider" ref="sliderContainer">
      <!-- 滑块轨道 -->
      <div class="track" :style="{ left: leftHandle + '%', right: (100 - rightHandle) + '%' }"></div>
      <!-- 左手柄 -->
      <div class="handle" :style="{ left: leftHandle + '%' }" @mousedown="startDrag(1)">
        {{ formatHour(rangeValue[0]) }}
      </div>
      <!-- 右手柄 -->
      <div class="handle" :style="{ left: rightHandle + '%' }" @mousedown="startDrag(2)">
        {{ formatHour(rangeValue[1]) }}
      </div>
    </div>
  </div>
</template>

脚本部分

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

const rangeValue = ref([8, 18])
const sliderContainer = ref(null)
let draggingHandle = 0
let startX = 0
let startValue = 0

const leftHandle = computed(() => {
  return (rangeValue.value[0] / 24) * 100
})

const rightHandle = computed(() => {
  return (rangeValue.value[1] / 24) * 100
})

const startDrag = (handle) => {
  draggingHandle = handle
  startX = event.clientX
  // 记录当前手柄的初始值
  startValue = handle === 1 ? rangeValue.value[0] : rangeValue.value[1]
  
  document.addEventListener('mousemove', handleDrag)
  document.addEventListener('mouseup', stopDrag)
  // 阻止默认行为避免选中文字
  event.preventDefault()
}

const handleDrag = (event) => {
  if (!draggingHandle || !sliderContainer.value) return
  
  const containerRect = sliderContainer.value.getBoundingClientRect()
  // 计算鼠标相对于滑块容器的位置百分比
  const percent = ((event.clientX - containerRect.left) / containerRect.width) * 100
  // 转换为0-24的小时值
  const hour = Math.round((percent / 100) * 24)
  
  // 限制范围并更新值
  if (draggingHandle === 1) {
    const newLeft = Math.max(0, Math.min(hour, rangeValue.value[1] - 1))
    rangeValue.value = [newLeft, rangeValue.value[1]]
  } else {
    const newRight = Math.max(rangeValue.value[0] + 1, Math.min(hour, 24))
    rangeValue.value = [rangeValue.value[0], newRight]
  }
}

const stopDrag = () => {
  draggingHandle = 0
  document.removeEventListener('mousemove', handleDrag)
  document.removeEventListener('mouseup', stopDrag)
}

const formatHour = (value) => {
  return `${value}:00`
}
</script>

样式部分(补充基础样式)

<style scoped>
.range-container {
  width: 80%;
  margin: 40px auto;
}

.range-slider {
  position: relative;
  height: 6px;
  background: #e0e0e0;
  border-radius: 3px;
  cursor: pointer;
}

.track {
  position: absolute;
  top: 0;
  height: 100%;
  background: #42b983;
  border-radius: 3px;
}

.handle {
  position: absolute;
  top: -12px;
  width: 28px;
  height: 28px;
  margin-left: -14px;
  background: white;
  border: 2px solid #42b983;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  font-size: 12px;
}

.handle:active {
  cursor: grabbing;
}
</style>

关键说明

  • 用(hour / 24) * 100将0-24小时转换为滑块的百分比位置,确保手柄在容器内正确分布。
  • 拖动时限制左右手柄的边界:左手柄不能超过右手柄,右手柄不能低于左手柄,且范围在0-24之间。
  • 使用Vue3的<script setup>语法,更符合Vue3的开发习惯,同时保证响应式更新。

内容的提问来源于stack exchange,提问作者MAHA OUEGHLANI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:05:19