Ошибка выделения текста в Mobile Safari с помощью iframes и ontouchstart - PullRequest
10 голосов
/ 29 июля 2011

В моем веб-приложении есть фреймы с разными z-индексами.Я обнаруживаю touchstart события на некоторых элементах в фреймах.Однако, если у меня есть поле ввода текста, перекрывающее элемент, захватывающий touchstart, поле ввода начинает работать хаотично: при повторном нажатии на поле не фокусируется его, вы не можете выделить любой текст, но вы можете ввестив текстовом поле.

Похоже, что единственным решением может быть прекращение захвата touchstart событий в фоновом фрейме.Я бы предпочел решение типа прозрачного div для захвата событий в качестве посредника, но я пока не получил этого.Есть ли другие обходные пути?

Пример страницы на jsfiddle , но вот код:

<!DOCTYPE html> 
<html> 
    <head> 
        <style type='text/css'> 
            iframe {
                position:absolute;
            }
            #background {
                border: solid 3px red;
                z-index:1;
                width: 20em;
                height: 20em;
            }
            #foreground, #foreground2 {
                border: solid 2px yellow;
                z-index:2;
                top: 15em;
                height: 5em;
            }
            #foreground2 {
                top: 22em;
            }
        </style> 

        <script type='text/javascript'> 
            window.onload=function(){
                document.getElementById("foreground").contentDocument.write("<input type='text' value='text'/><input type='text'/>");
                document.getElementById("foreground2").contentDocument.write("<input type='text' value='text'/><input type='text'/>");

                document.getElementById("background").addEventListener("touchstart", function() {
                    console.log("touch");
                });
            }
        </script> 
    </head> 
    <body> 
        <iframe id=background></iframe> 
        <iframe id=foreground></iframe> 
        <iframe id=foreground2></iframe> 
    </body>
</html> 

Ответы [ 3 ]

4 голосов
/ 15 июля 2015

Хотя эта ветка довольно старая, я просто хотел подтвердить, что эта ошибка все еще сохраняется в последней версии iOS (8.4) на всех устройствах (iPhone / iPad).

После некоторого тестирования я могу подтвердить, что он всегда появляется при следующих обстоятельствах:

  • При использовании HTML-тега iframe / object / embed для отображения содержимого HTML в сочетании с привязками событий касания javascript (touchstart / touchend и т. Д.) К элементам внутри этого содержимого HTML. Когда пользователь касается элемента ввода внутри этого тега iframe / object / embed второй раз (иногда больше), все, что он пытается ввести с помощью экранной клавиатуры, больше не появляется внутри поля ввода. (что интересно, подсказки над клавиатурой по-прежнему реагируют на все, что вводит пользователь, но больше не отображаются в поле ввода). Иногда возможно удалить контент через клавишу возврата в поле ввода, но не добавлять ничего.

Кажется, существуют следующие варианты:

  1. Событие касания привязывается непосредственно к элементу ввода, что приводит к этой ошибке.

  2. Событие касания связано с родительским элементом, внутри которого находится элемент ввода (не обязательно должен быть прямым потомком).

  3. Элемент ввода визуально расположен поверх элемента с привязкой события касания. Неважно, где этот элемент находится внутри DOM или есть ли перекрывающие элементы между сенсорным элементом и полем ввода. Связанный с прикосновением элемент также не должен быть видимым, чтобы это произошло (например, когда другие элементы находятся поверх него). Как только пользователь касается области поля ввода, за которой находится сенсорный элемент, появляется ошибка. Это интересно, потому что, если элемент ввода только частично перекрывает сенсорный связанный элемент, касание той части ввода, где сенсорный связанный элемент не находится позади, не приведет к этой ошибке.

Решения: Во-первых: кажется, что это не поможет, если вы поэкспериментируете с protectDefault / stopPropagation и другими подобными вещами на элементе с привязкой. Неважно, что происходит с привязкой события / прикосновения к связанному элементу (я проверял это, он не вызывается / не срабатывает при появлении ошибки). Даже такие CSS-решения, как «указатель-события: ни один» в элементе с привязкой к прикосновению, не помогают. Поэтому следующие решения - наша единственная надежда:

  1. Динамически связывайте события касания, как предложено в этой теме, чтобы они были активны только тогда, когда они вам действительно нужны, и удаляйте их, когда нет, чтобы предотвратить все 3 случая, описанных выше.

  2. Переместите элементы или контейнеры с привязками событий касания, когда входной элемент находится впереди. Достаточно использовать CSS-преобразования и т. Д., Так как даже визуальное перемещение их от полей ввода работает. (см. вариант ошибки 3 выше). Так, в зависимости от вашего макета, например, если у вас есть боковая панель с полем поиска, которое перемещается со стороны вашей страницы и накладывает основной контент, не стоит накладывать основной контент, а вместо этого перемещать его в сторону.

  3. Используйте 'display: none' для элементов с привязкой событий касания, когда они не используются. Это единственное свойство css, которое, по-видимому, решает вариант ошибки 3. 'visibility: hidden' в моих тестах не действовал. Элементы с «display: none» больше не влияют на входные элементы с этой ошибкой. В случае, если вы строите одностраничный пейджер, вы должны рассмотреть страницы настроек или «элементы с привязкой», которые не отображаются ни для чего. Это предотвратит ошибку варианта 3.

  4. Конечно, лучше всего избегать использования тегов iframe / object / embed для отображения другого контента, пока существует эта ошибка.

1 голос
/ 09 сентября 2011

Не было «хорошего» решения.В моей конкретной ситуации, поскольку мне не нужно было отслеживать сенсорные события в «фоновых» фреймах, я просто отключил этот обработчик событий в фоновом режиме и добавил их обратно на передний план.К сожалению, в Javascript нет способа узнать, какие события прикреплены к узлу.В моем случае я отслеживал это независимо, и это работало нормально.

Интересно, что это происходит, даже если вы просто пытаетесь захватить события сенсорного запуска в пределах одного iframe: введите описание ссылки здесь .Я подозреваю, что обходной путь

0 голосов
/ 15 сентября 2011

Дэвид прав.Я не знаю, как обойти эту проблему, я потратил много времени, пытаясь ее найти.Единственное, что нужно сделать, это удалитьEventListener для всех сенсорных событий, когда открыт оверлей iframe, и затем повторно добавить addEventListener, когда iframe закрывается.Единственный способ сделать это - использовать общедоступную именованную функцию в качестве прослушивателя событий, чтобы вы могли ее удалить.Когда-нибудь будет реализован DOM-уровень 3, и вы сможете использовать функцию 'name' для анонимного или приватного прослушивателя событий с помощью eventListenerList (), но ни один браузер пока не использует это.

Интересно, чтоэта проблема возникает только тогда, когда элементы формы в iframe располагаются непосредственно над элементами со слушателями событий касания.Элементы формы в iframe, которые не находятся над прослушиваемыми элементами сенсорного события, будут работать просто отлично.В некоторых случаях (не мое) и альтернативное решение может изменить высоту элемента фона на 1 пиксель, когда iframe открыт, и сбросить его высоту до полного размера, когда наложение iframe закрывается.

...