为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

守着星空守着你 2023-04-27 16:35:30
我有两个拇指的滑块。拇指可以沿着滑块(线)一直移动,这可以通过增加或减少它们来实现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.
查看完整描述

1 回答

?
桃花长相依

TA贡献1860条经验 获得超8个赞

我一直在挖掘并偶然发现了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 



查看完整回答
反对 回复 2023-04-27
  • 1 回答
  • 0 关注
  • 76 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信