Как лучше всего имитировать наведение мыши в мобильных браузерах с помощью сенсорных событий?

У меня есть простой пользовательский интерфейс, который позволяет пользователям настольных браузеров щелкать ячейку в сетке и, удерживая кнопку мыши, перемещать мышь, чтобы очень быстро выделить несколько ячеек. Я выполняю это с помощью событий mousedown, mouseover и mouseup на document и использую логический флаг, чтобы определить, удерживается ли кнопка мыши нажатой или нет. Он отлично работает в настольных браузерах.

Однако проблема связана с мобильными браузерами. Эти события мыши не существуют, и я знаю, что вместо этого нам нужно использовать события touch, но после обширного поиска в Google, SO и т. д. я не могу найти последовательный, работоспособный способ сделать то же самое в мобильных браузерах. .

Самое близкое, что я видел, это захват начала с помощью touchstart, а затем отслеживание движения пальца с помощью свойств touchmove и evt.touches[0].clientX/Y. Есть ли лучший/более простой способ сделать это, или мы вынуждены в основном проверять координаты экрана с помощью clientX/Y, чтобы выяснить, над каким элементом DOM мы «зависаем», и соответственно выделяем элемент DOM?


person HartleySan    schedule 28.02.2020    source источник
comment
Вы, безусловно, на правильном пути с touchstart, touchmove и touchend, очевидно, есть document.elementFromPoint(event.clientX, event.clientY); , согласно этой теме   -  person Adam H    schedule 29.02.2020
comment
Этот метод document.elementFromPoint очень удобен. Это сэкономит много времени (надеюсь). Спасибо.   -  person HartleySan    schedule 29.02.2020


Ответы (2)


Я думаю, вы на правильном пути решения. Я должен был сделать что-то подобное на этой неделе. Один совет:

Когда срабатывает событие onTouchStart, установите событие onTouchMove на document, чтобы оно срабатывало, даже если пользователь выходит за пределы элемента, вызвавшего начальное событие. (Это может не относиться к вашему конкретному пользовательскому интерфейсу)

person Gerard    schedule 28.02.2020
comment
Спасибо, Джерард. Да, я установил touchmove для объекта document, так что у меня все получилось. Итак, в основном, для каждого touchmove я должен вычислить, нахожу ли я новый элемент DOM или удаляюсь от существующего элемента DOM, и делаю ли я все, что хочу, соответственно? По сути, нам нужно вручную перекодировать mouseover и mouseout для сенсорных событий, да? Фу! Какая боль. - person HartleySan; 29.02.2020

Спасибо всем за помощь в решении этой проблемы. Метод document.elementFromPoint действительно был ключом, который сделал все это возможным без тонны дополнительного кода.

Вот пример используемого кода, позволяющего подсвечивать ячейки сетки, которые я искал как на рабочем столе, так и на мобильных устройствах, когда пользователь щелкает мышью / касается пальцем экрана и начинает перемещать мышь / палец вокруг:

var isTouchDevice = 'ontouchstart' in document.documentElement;
var isActivelySelecting = false;
var currHoverTarget = null;

if (isTouchDevice) { // Mobile version
    document.addEventListener('touchstart', (evt) => {
        var target = evt.target;

        if (target.classList.contains('class-name-of-selectable-grid-cells')) {
            isActivelySelecting = true;
            currHoverTarget = target;
            toggleSelection(target); // Function for storing selected cells in an array

            // For turning off text highlighting as you select cells
            document.querySelector('body').classList.add('noHighlighting');

            // Stops screen from scrolling on mobile while selecting cells.
            evt.preventDefault();
        }
    }, {
        passive: false // Needed to avoid errors in some browsers.
    });

    document.addEventListener('touchmove', (evt) => {
        if (isActivelySelecting) {
            var target = evt.target;

            if (target.classList.contains('class-name-of-selectable-grid-cells')) {
                var x = evt.touches[0].clientX;
                var y = evt.touches[0].clientY;
                var hoveredElem = document.elementFromPoint(x, y); // The secret sauce

                // Only true when going from one DOM element to another.
                // Basically simulates the mouseover event for desktop browsers.
                if (hoveredElem !== currHoverTarget) {
                    currHoverTarget = hoveredElem;
                    toggleSelection(hoveredElem); // Function for storing selected cells in an array
                }
            }
        }
    });

    document.addEventListener('touchend', () => {
        isActivelySelecting = false;
        currHoverTarget = false;

        document.querySelector('body').classList.remove('noHighlighting');
    });
} else { // Desktop version
    document.addEventListener('mousedown', (evt) => {
        var target = evt.target;

        if (target.classList.contains('class-name-of-selectable-grid-cells')) {
            isActivelySelecting = true;
            toggleSelection(target); // Function for storing selected cells in an array

            // For turning off text highlighting as you select cells
            document.querySelector('body').classList.add('noHighlighting');
        }
    });

    document.addEventListener('mouseover', (evt) => {
        if (isActivelySelecting) {
            var target = evt.target;

            if (target.classList.contains('class-name-of-selectable-grid-cells')) {
                toggleSelection(target); // Function for storing selected cells in an array
            }
        }
    });

    document.addEventListener('mouseup', () => {
        isActivelySelecting = false;

        document.querySelector('body').classList.remove('noHighlighting');
    });
}
person HartleySan    schedule 29.02.2020