Почему это событие щелчка вызывается для несвязанного элемента? - PullRequest
0 голосов
/ 16 марта 2020

Я работаю над этой подсказкой, где, если вы наведете на нее курсор мыши, она покажет подсказку:

Но если вы нажмете на нее (пальцем), то она покажу полный экран (для мобильной поддержки):

Код выглядит следующим образом:

export default function Tooltip({ message, children }: Props) {
    const [showSmallTip, setShowSmallTip] = useState(false);
    const [showBigTap, setShowBigTip] = useState(false);
    const ref = useRef(null);
    const pos = useBoundingBox(ref);

    const handleMouseEnter = useCallback(() => {
        setShowSmallTip(true);
    }, [setShowSmallTip]);

    const handleMouseLeave = useCallback(() => {
        setShowSmallTip(false);
    }, [setShowSmallTip]);

    const handleTap = useCallback(() => {
        console.log("TAP!")
        setShowBigTip(true);
        setShowSmallTip(false);
    }, [setShowBigTip]);

    const closeFullscreen = useCallback((ev:MouseEvent<HTMLElement>) => {
        console.log('CLOSE!!!')
        ev.stopPropagation();
        setShowBigTip(false);
        setShowSmallTip(false);
    }, [setShowBigTip]);

    const onTap = useTap(handleTap);

    return <>
        <Wrapper ref={ref} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} {...onTap}>
            {children}
        </Wrapper>
        {showSmallTip ? <End container={SCROLL_ROOT}><StyledTooltip style={{ top: pos.bottom, left: (pos.left + pos.right) / 2 }}>{message}</StyledTooltip></End> : null}
        {showBigTap ? <End><FullscreenTip onClick={closeFullscreen}><FullscreenText>{message}</FullscreenText></FullscreenTip></End>:null}
    </>
}

Где useTap:

export default function useTap<T = Element>(callback: VoidCallback, options?: Options): TouchEvents<T> {
    const data = useRef<TouchData>(Object.create(null));

    return useMemo<TouchEvents<T>>(() => {
        const opt = { ...DEFAULT_OPTIONS, ...options } as Required<Options>;

        return {
            onTouchStart(ev) {
                data.current = {
                    time: ev.timeStamp,
                    x: ev.changedTouches[0].screenX,
                    y: ev.changedTouches[0].screenY,
                }
            },
            onTouchEnd(ev) {
                const mx = ev.changedTouches[0].screenX - data.current.x;
                const my = ev.changedTouches[0].screenY - data.current.y;
                const moved = Math.sqrt(mx**2 + my**2);
                const elapsed = ev.timeStamp - data.current.time;
                if (moved < opt.moveThreshold && elapsed < opt.pressDelay) {
                    // setTimeout(() => {
                        callback();
                    // }, 0);
                }
            }
        }
    }, [callback, options])
}

Проблема, с которой я столкнулся, заключается в том, что когда вы нажимаете на значок, он открывается и сразу же закрывает полноэкранную подсказку. то есть он печатает

TAP!
CLOSE!!!

одним нажатием.

Теперь я знаю, touchend срабатывает до click, но я не могу понять, почему это даже имеет значение ?? Если вы посмотрите на мое размещение обработчиков {...onTap} и onClick={closeFullscreen}, то они братья и сестры. События не должны пузыриться таким образом (ни в собственном DOM, ни в React's VDOM ), и я, конечно, не нажал на <FullscreenTip>, так как же closeFullscreen запускается?

<End> это портал.

1 Ответ

1 голос
/ 16 марта 2020

DEMO

Попробуйте позвонить ev.preventDefault() на onTouchEnd.

Согласно spe c touchend событие «отменяемое» , что означает, что вы можете использовать .preventDefault() для предотвращения событий мыши.

Если для этого события вызывается метод protectDefault, он должны предотвращать любые действия по умолчанию, вызванные любыми событиями касания, связанными с той же активной точкой касания, включая события мыши или прокрутку.

enter image description here

...