如何拖动一个元素并确保光标不会比它快?

我有两个拇指的滑块。拇指可以沿着滑块(线)一直移动,这可以通过增加或减少它们来实现margin-left,但是为了让它们移动,状态move必须是true,当每个拇指触发事件时都会发生onClickDown。但是,如果事件onClickedUp被触发,光标离开拇指或滑块的区域,move设置为false,这会使拇指停止移动。没关系,就是这个主意。

问题是光标可能比拇指的移动速度更快,如下面的 gif 所示,是什么使光标离开拇指区域并设置为 false,即使这不是用户想要的move

https://i.stack.imgur.com/hAXVP.gif

因此,为了使滑块正常工作,用户在移动拇指时必须格外小心,这是一个非常烦人的用户体验。


简而言之,我需要做的是确保光标不会比拇指移动得更快,无论我是否必须减慢光标或增加拇指的速度都没有关系。


我怎么能那样做?


这是我的代码和一些注释:


import React, { Fragment } from 'react'


import './Filter.css'



const Filter = props => {


    const sliderRef = React.useRef() // => main parent div


    const initial_position = 0 

    const end_position = 200 


    const initial_min_value = 5 // => Initial price 

    const initial_max_value = 1290 // => Final price


    let [thumb1_position, setValueThumb1] =  React.useState(0)

    let [thumb2_position, setValueThumb2] =  React.useState(0)

    let [min_value, setMinValue] =  React.useState(initial_min_value)

    let [max_value, setMaxValue] =  React.useState(initial_max_value)

    let [move, setMove] =  React.useState(false) // => Enable thumbs to move

    

    // Ensure that the thumb_2 will be in the end of the slider at first

    React.useEffect(() => {

        setValueThumb2(sliderRef.current.offsetWidth - 5)

    }, [])



    // Here I get the position of the cursor within the element (slider) and move the thumbs based on it.

    const handleChange = e => {


        let thumb_class = e.target.className


        var rect = sliderRef.current.getBoundingClientRect();

        const current_position = e.clientX - rect.left; // X position within the element.

守着星空守着你
浏览 95回答 1
1回答

桃花长相依

我一直在挖掘并偶然发现了setPointerCapture()解决我的问题的方法。它的功能是完全按照我对我的代码所做的,但使用pointer events. 它使元素在 pointerdown 事件上移动并使其在 pointerup 事件上停止移动。因为它几乎完成了我需要做的所有事情,所以我可以摆脱我正在使用的一些功能。事实上,唯一保留的功能是handleChange. 除此之外,我还删除了move状态,但我必须添加一些refs才能获取每个元素。这是新代码:import React, { Fragment } from 'react'import './Filter.css'const Filter = props => {    const sliderRef = React.useRef() // => main parent div    const sliderRef = React.useRef() // => Div que engloba o slider    const thumb_1_Ref = React.useRef() // => Div que engloba o slider    const thumb_2_Ref = React.useRef() // => Div que engloba o slider    const price_thumb_1_Ref = React.useRef() // => Div que engloba o slider    const price_thumb_2_Ref = React.useRef() // => Div que engloba o slider        const initial_position = 0         const initial_min_value = 5 // => Initial price     const initial_max_value = 1290 // => Final price    let [thumb1_position, setValueThumb1] =  React.useState(0)    let [thumb2_position, setValueThumb2] =  React.useState(0)    let [mobile_thumb1_position, setValueMobileThumb1] =  React.useState(0)    let [mobile_thumb2_position, setValueMobileThumb2] =  React.useState(0)    let [min_value, setMinValue] =  React.useState(initial_min_value)    let [max_value, setMaxValue] =  React.useState(initial_max_value)        // Ensure that the thumb_2 will be in the end of the slider at first    React.useEffect(() => {        setValueThumb2(sliderRef.current.offsetWidth - 5)    }, [])    let slider    let slider_price    const beginSliding = e => {        slider.onpointermove = slide        slider.setPointerCapture(e.pointerId)    }        const stopSliding = e => {        slider.onpointermove = null        slider.releasePointerCapture(e.pointerId)    }        const slide = e => {        const thumb_class = e.target.className        let rect = sliderRef.current.getBoundingClientRect()        let current_position = e.clientX - rect.left                 if (thumb_class.includes('right-thumb')) {            current_position = current_position - sliderRef.current.offsetWidth            if (current_position >= initial_position) {                current_position = initial_position            }            if (current_position <= mobile_thumb1_position - 175) {                current_position = mobile_thumb1_position - 175            }                        setValueMobileThumb2(current_position)        }                 if (thumb_class.includes('left-thumb')) {            if (current_position <= initial_position) {                current_position = initial_position            }            if (current_position >= mobile_thumb2_position + 175) {                current_position = mobile_thumb2_position + 175            }            setValueMobileThumb1(current_position)        }                slider.style.transform = `translate(${current_position}px)`        slider_price.style.transform = `translate(${current_position}px)`    }                const handleChange = e => {        const thumb_class = e.target.className        if (thumb_class.includes('left-thumb')) {            slider = thumb_1_Ref.current;            slider_price = price_thumb_1_Ref.current;            slider.onpointerdown = beginSliding;            slider.onpointerup = stopSliding;            if (mobile_thumb1_position - initial_position < 1) {                setMinValue(initial_min_value)            } else {                setMinValue((mobile_thumb1_position - initial_position) * 6.45)            }        } else if (thumb_class.includes('right-thumb')) {                        slider = thumb_2_Ref.current;            slider_price = price_thumb_2_Ref.current;            slider.onpointerdown = beginSliding;            slider.onpointerup = stopSliding;            if (mobile_thumb2_position > -1) {                setMaxValue(initial_max_value)            } else {                setMaxValue((mobile_thumb2_position + 200) * 6.45)            }        }    }    return (        <Fragment>            <div>                <h6 style={{marginBottom: '35px'}}>PRICE FILTER</h6>                <div className="range-container"                    onMouseMove={(e) => handleChange(e)}                    ref={sliderRef}                >                    <div className="range"                    >                        <span                             className="rounded-circle left-thumb"                            style={{                                width:'15px',                                height: '15px',                                backgroundColor: 'red',                                marginTop: '-6px',                                marginLeft: thumb1_position - 7 + 'px'                            }}                            ref={thumb_1_Ref}                        ></span>                        <span                             className="rounded-circle right-thumb"                            style={{                                width:'15px',                                height: '15px',                                backgroundColor: 'black',                                marginTop: '-6px',                                marginLeft: thumb2_position - 7 + 'px'                            }}                            ref={thumb_2_Ref}                        ></span>                        <p style={{                            marginLeft: thumb1_position - 15 + 'px',                            position: 'absolute',                            marginTop: '15px'}}                            ref={price_thumb_1_Ref}                        > {Math.floor(min_value)}                        </p>                        <p style={{                            marginLeft: thumb2_position - 15 + 'px',                            position: 'absolute',                            marginTop: '15px'}}                            ref={price_thumb_2_Ref}                        > {Math.floor(max_value)}                        </p>                    </div>                </div>            </div>        </Fragment>    )}export default Filter 
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript