tiny-vue icon indicating copy to clipboard operation
tiny-vue copied to clipboard

🐛 [Bug]: [slider] Slider component vertical mode, drag to the anchor will jump

Open yoyo201626 opened this issue 2 years ago • 5 comments

Version

opentiny/[email protected]

Vue Version

3

Link to minimal reproduction

https://opentiny.design/tiny-vue/zh-CN/os-theme/components/slider

Step to reproduce

  1. 滚动到下面 图片

  2. 点击锚点 图片

What is expected

No response

What is actually happening

No response

Any additional comments (optional)

No response

yoyo201626 avatar Nov 24 '23 09:11 yoyo201626

Bot detected the issue body's language is not English, translate it automatically.


Title: 🐛 [Bug]: Slider component in vertical mode, dragging to the anchor point will jump

Issues-translate-bot avatar Nov 24 '23 09:11 Issues-translate-bot

It seems that the component didn’t calculate the position after scroll

// renderless/src/slider/index.ts
// bindMouseDown()
+ api.bindResize()
const currentValue  = api.calculateValue(event)

Huauauaa avatar Nov 25 '23 05:11 Huauauaa

It seems that the component didn’t calculate the position after scroll

// renderless/src/slider/index.ts
// bindMouseDown()
+ api.bindResize()
const currentValue  = api.calculateValue(event)

@Huauauaa I think more critical is this code in packages\renderless\src\slider\index.ts#calculateValue :

  (event) => {
    let currentValue = 0

    if (state.sliderSize == 0) {
      const handleEl = vm.$refs.slider
      state.sliderSize = handleEl['client' + (props.vertical ? 'Height' : 'Width')]
      state.sliderOffset = handleEl.getBoundingClientRect()
    }

    const offset = state.sliderOffset as DOMRect

    if (event.type === 'touchmove' || event.type === 'touchstart' || event.type === 'touchend') {
      if (props.vertical) {
        currentValue = props.max - ((event.touches[0].pageY - offset.top) / state.sliderSize) * state.rangeDiff
      } else {
        currentValue = props.min + ((event.touches[0].pageX - offset.left) / state.sliderSize) * state.rangeDiff
      }
    } else {
      if (props.vertical) {
        currentValue = props.max - ((event.pageY - offset.top) / state.sliderSize) * state.rangeDiff
      } else {
        currentValue = props.min + ((event.pageX - offset.left) / state.sliderSize) * state.rangeDiff
      }
    }
    return currentValue
  }

event.pageY is the Y coordinate relative to the entire document, but offset.top which get from Element.getBoundingClientRect() is relative to the Viewport

yoyo201626 avatar Nov 30 '23 12:11 yoyo201626

应该选择使用相对 Viewport 的定位来计算

因为当前没有好办法来准确获取某个Element的相对于document的定位。

这对于鼠标事件event来说,只要把event.pageY改成event.clientY就可以。

但是对于当前锚点元素handleEl来说,为了减少回流,我们不能太频繁地使用Element.getBoundingClientRect()来获取相对于ViewPort的定位。这是需要解决的。

yoyo201626 avatar Dec 04 '23 08:12 yoyo201626

Bot detected the issue body's language is not English, translate it automatically.


You should choose to use positioning relative to the Viewport to calculate

Because there is currently no good way to accurately obtain the positioning of an Element relative to the document.

For the mouse event event, just change event.pageY to event.clientY.

But for the current anchor element handleEl, in order to reduce reflow, we cannot use Element.getBoundingClientRect() too frequently to obtain the position relative to the ViewPort. This needs to be addressed.

Issues-translate-bot avatar Dec 04 '23 08:12 Issues-translate-bot