Преглед изворни кода

refactor(scale-ruler): 重构刻度尺组件以优化性能和布局

- 移除不必要的 currentValue 状态管理
- 简化滚动计算逻辑,提高运行效率
- 调整样式结构,统一网格高度控制方式
- 删除冗余的指示器线条元素
- 移除气泡显示当前值的功能
- 优化初始化定位算法
- 清理未使用的计算属性和样式类名
- 统一使用系统窗口宽度获取方法
- 精简事件处理中的边界判断逻辑
- 更新样式定义以适配新的布局结构
mcbaiyun пре 2 месеци
родитељ
комит
b3104155ab
1 измењених фајлова са 15 додато и 57 уклоњено
  1. 15 57
      src/components/scale-ruler.vue

+ 15 - 57
src/components/scale-ruler.vue

@@ -1,6 +1,5 @@
 <template>
   <view class="ruler-wrapper" v-show="visible">
-    <view class="value-bubble" v-if="currentValue !== null">{{ currentValue }}{{ props.unit }}</view>
     <scroll-view
       class="ruler-scroll"
       scroll-x
@@ -16,17 +15,14 @@
           v-for="(g, idx) in gridList"
           :key="idx"
           class="grid-item"
-          :class="{ long: g.isLongGrid, labeled: g.showText }"
-          :style="{ width: props.gutter + 'px' }"
+          :class="{ long: g.isLongGrid }"
+          :style="{ width: props.gutter + 'px', height: g.showText ? '40px' : '24px' }"
         >
-          <view class="tick" :class="{ long: g.isLongGrid }"></view>
           <text v-if="g.showText" class="grid-num">{{ g.displayNum }}</text>
         </view>
       </view>
     </scroll-view>
-    <view class="indicator">
-      <view class="indicator-line"></view>
-    </view>
+    <view class="indicator"></view>
   </view>
 </template>
 
@@ -52,7 +48,6 @@ const emit = defineEmits(['update:value', 'change'])
 const instance = getCurrentInstance()
 const scrollLeft = ref(0)
 const actualScrollLeft = ref(0)
-const currentValue = ref<number | null>(null)
 
 // prepare grid
 const totalUnits = computed(() => Math.round((props.max - props.min) / props.step))
@@ -89,47 +84,21 @@ const offsetScroll = computed(() => extraGridCount * props.gutter)
 const windowWidth = uni?.getSystemInfoSync?.().windowWidth || 375
 const halfWindow = windowWidth / 2
 
-// centered positions for extremes
-const minCenterLeft = computed(() => offsetScroll.value - halfWindow + props.gutter / 2)
-const maxCenterLeft = computed(() => totalUnits.value * props.gutter + offsetScroll.value - halfWindow + props.gutter / 2)
-
 // initial position
 onMounted(() => {
   // center on initial value
   const initIndex = Math.round((props.initialValue - props.min) / props.step)
-  // use computed windowWidth to center the initial index under the indicator
-  scrollLeft.value = initIndex * props.gutter + offsetScroll.value - halfWindow + props.gutter / 2
+  scrollLeft.value = initIndex * props.gutter + offsetScroll.value - (uni?.getSystemInfoSync?.().windowWidth || 375) / 2 + props.gutter / 2
 })
 
 function onScroll(e: any) {
   const left = e?.detail?.scrollLeft ?? e?.detail?.scrollLeft ?? 0
   actualScrollLeft.value = left
-  // compute index under the centered indicator (float)
-  const centerPos = left + halfWindow - offsetScroll.value - props.gutter / 2
-  const idxFloat = centerPos / props.gutter
-  // calculate actual scrollable max
-  const maxScroll = Math.max(0, totalWidth.value - windowWidth)
-  // if center would go left of min, clamp scrollLeft to minCenterLeft and emit min
-  if (idxFloat <= 0) {
-    const clamped = Math.min(Math.max(minCenterLeft.value, 0), maxScroll)
-    scrollLeft.value = clamped
-    actualScrollLeft.value = clamped
-    emit('update:value', props.min)
-    return
-  }
-  // if center would go right of max, clamp to maxCenterLeft and emit max
-  if (idxFloat >= totalUnits.value) {
-    const clamped = Math.min(Math.max(maxCenterLeft.value, 0), maxScroll)
-    scrollLeft.value = clamped
-    actualScrollLeft.value = clamped
-    emit('update:value', props.max)
-    return
-  }
-  const idx = Math.round(idxFloat)
+  // compute index under the centered indicator
+  const idx = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)
   let value = idx * props.step + props.min
   if (value < props.min) value = props.min
   if (value > props.max) value = props.max
-  currentValue.value = value
   emit('update:value', value)
 }
 
@@ -140,14 +109,9 @@ function adjustScrollPosition() {
   const idx = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)
   // compute target scrollLeft that centers this index
   const targetLeft = idx * props.gutter + offsetScroll.value - halfWindow + props.gutter / 2
-  // compute centered positions for min and max so extremes map to centered
-  const minCenterLeft = 0 + offsetScroll.value - halfWindow + props.gutter / 2
-  const maxCenterLeft = totalUnits.value * props.gutter + offsetScroll.value - halfWindow + props.gutter / 2
-  // actual scrollable bounds
+  // clamp to valid scroll range
   const maxScroll = Math.max(0, totalWidth.value - windowWidth)
-  // clamp target to the centered min/max first, then to actual scroll range
-  const bounded = Math.min(Math.max(targetLeft, minCenterLeft), maxCenterLeft)
-  const clamped = Math.min(Math.max(bounded, 0), maxScroll)
+  const clamped = Math.min(Math.max(targetLeft, 0), maxScroll)
   scrollLeft.value = clamped
 }
 
@@ -160,22 +124,16 @@ function onTouchEnd() {
   let value = idx * props.step + props.min
   if (value < props.min) value = props.min
   if (value > props.max) value = props.max
-  currentValue.value = value
   emit('change', value)
 }
 </script>
 
 <style scoped>
-.ruler-wrapper { position: relative; height: 90rpx; display:flex; align-items:center; padding-top:20rpx }
-.value-bubble { position: absolute; left: 50%; top: 0; transform: translateX(-50%); background: #ff6a00; color: #fff; padding:6rpx 14rpx; border-radius: 18rpx; font-weight:700; box-shadow: 0 6rpx 18rpx rgba(255,106,0,0.18); z-index: 20 }
-.ruler-scroll { width: 100%; height: 90rpx; overflow: hidden }
-.ruler-inner { display:flex; align-items:flex-end; padding-bottom: 8rpx }
-.grid-item { display:flex; flex-direction:column; align-items:center; justify-content:flex-end; height: 60px; position: relative }
-.grid-item.labeled { height: 80px }
-.tick { width: 2px; background: #ccc; transition: background-color .12s, height .12s }
-.tick.long { height: 34px; background: #999 }
-.grid-item.labeled .grid-num { margin-top:6rpx; color:#333; font-size:24rpx }
-.grid-num { font-size: 20rpx; color: #666 }
-.indicator { position: absolute; left: 50%; top: 18rpx; transform: translateX(-50%); width: 36rpx; height: 54rpx; display:flex; align-items:center; justify-content:center; pointer-events:none }
-.indicator-line { width: 2px; height: 100%; background: #ff6a00; box-shadow: 0 2px 6px rgba(255,106,0,0.25); border-radius:1px }
+.ruler-wrapper { position: relative; height: 80rpx; display:flex; align-items:center }
+.ruler-scroll { width: 100%; height: 80rpx }
+.ruler-inner { display:flex; align-items:flex-end }
+.grid-item { width: 10px; height: 24px; display:flex; align-items:flex-end; justify-content:center }
+.grid-item.long { height: 40px }
+.grid-num { font-size: 24rpx; color: #666 }
+.indicator { position: absolute; left: 50%; top: 0; transform: translateX(-50%); width: 2px; height: 100%; background: #ff6a00 }
 </style>