优雅实现!自定义滚动刻度选择器,精准选择无压力

在移动端开发中,滚动刻度选择器 是一个很常见的需求。他主要体现在体重、血糖、身高等选择。今天,我将分享一个高度自定义的滚动刻度选择器组件,它不仅支持整数和小数两种模式,还提供了流畅的滚动体验和精准的刻度定位。

🌟 组件亮点

  1. 双模式支持:无缝切换整数和小数选择模式
  2. 精准吸附:滚动结束后自动吸附到最近刻度
  3. 视觉层次:主刻度、中等刻度和次刻度清晰区分
  4. 边界处理:滚动到两端时自动锁定边界值
  5. 响应式设计:完美适配不同屏幕尺寸

🚀 实际效果展示

🔧 核心实现思路

1. 刻度系统设计

js 复制代码
// 刻度线类型定义
enum ScaleMarkerType {
  MAJOR = 'major',   // 主刻度(长线)
  MEDIUM = 'medium', // 中等刻度
  MINOR = 'minor'    // 次刻度(短线)
}

// 动态生成刻度系统
const initializeScale = () => {
  scaleMarkers.value = []
  const range = normalizedMaxValue.value - normalizedMinValue.value
  const steps = Math.floor(range / stepSize.value)

  for (let i = 0; i <= steps; i++) {
    const currentValue = normalizedMinValue.value + i * stepSize.value
    
    // 智能识别刻度类型
    let markerType: ScaleMarkerType
    if (props.isIntegerScale) {
      markerType = currentValue % 10 === 0 
        ? ScaleMarkerType.MAJOR 
        : currentValue % 5 === 0 
          ? ScaleMarkerType.MEDIUM 
          : ScaleMarkerType.MINOR
    } else {
      markerType = Number.isInteger(currentValue) 
        ? ScaleMarkerType.MAJOR 
        : currentValue % 1 === 0.5 
          ? ScaleMarkerType.MEDIUM 
          : ScaleMarkerType.MINOR
    }
    
    scaleMarkers.value.push({ type: markerType })
  }
}

2. 滚动位置与数值的精准映射

js 复制代码
// 处理滚动事件
const handleScroll = (event: any) => {
  const scrollOffset = event.detail.scrollLeft
  const validOffset = Math.max(0, Math.min(scrollOffset, maxScrollLeft.value))
  
  // 计算当前值 = 最小值 + (偏移量/刻度宽度)*步长
  const steps = Math.round(validOffset / markerWidth.value)
  const calculatedValue = normalizedMinValue.value + steps * stepSize.value
  
  // 确保值在[min,max]范围内
  const clampedValue = Math.min(
    Math.max(calculatedValue, normalizedMinValue.value),
    normalizedMaxValue.value
  )

  // 根据模式格式化输出
  const finalValue = props.isIntegerScale 
    ? Math.round(clampedValue) 
    : Number(clampedValue.toFixed(1))

  emit('valueChange', finalValue)
}

3. 滚动结束自动吸附

js 复制代码
// 滚动结束处理(自动吸附到最近刻度)
const handleScrollEnd = () => {
  const currentPos = initialScrollPosition.value
  const nearestStep = Math.round(currentPos / markerWidth.value)
  initialScrollPosition.value = nearestStep * markerWidth.value
}

🎨 视觉层次设计

通过CSS实现清晰的视觉层次:

js 复制代码
.scale-marker {
  display: inline-block;
  width: 2px;
  background: #d2d2d2;
  position: relative;

  /* 不同类型刻度高度 */
  &.major { height: 40rpx; } /* 主刻度最高 */
  &.medium { height: 40rpx; }
  &.minor { height: 26rpx; } /* 次刻度最短 */
}

/* 中央指示线样式 */
.indicator-line {
  position: absolute;
  width: 6rpx;
  height: 55rpx;
  top: 0;
  background: var(--wui-color-theme, #007aff);
  left: 50%;
  transform: translateX(-50%);
  border-radius: 6rpx;
  z-index: 10; /* 确保在最上层 */
}

💡 使用示例

js 复制代码
<template>
  <ScrollPicker 
    :initial-value="weight"
    :min-value="0"
    :max-value="200"
    :marker-spacing="12"
    :is-integer-scale="true"
    @value-change="handleWeightChange"
  />
</template>

<script setup>
import { ref } from 'vue'
import ScrollPicker from '@/components/ScrollPicker.vue'

const weight = ref(65)

const handleWeightChange = (newValue) => {
  weight.value = newValue
  console.log(`当前体重: ${newValue}kg`)
}
</script>

🏆 性能优化点

  1. 虚拟滚动:只渲染可视区域内的刻度,大幅提升性能
  2. 防抖处理:滚动事件添加防抖,避免频繁触发重绘
  3. 边界缓存:预计算边界值,避免滚动时重复计算
  4. CSS硬件加速:使用transform提升动画性能

🌈 应用场景

身高、体重、血糖、血压等

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax