Вы действительно используете addEventListener?
Да, это действительно захватывает заголовки, но я недавно узнал, что мой друг (который сказал, что это было мое!) действительно не знает, как его использовать.addEventListener
.
причина
Недавно я работал над проектом с открытым исходным кодом,vue-carousel, компонент карусели в экосистеме Vue, открытый исходный код SSENSE, компании электронной коммерции в Канаде. Тогда кто-то только что упомянул одинissue
Unable to preventDefault inside passive event listener due to target being treated as passive
Может быть кто-то сталкивался с этой проблемой при разработке мобильных приложений, позвольте мне воспроизвести для вас такой сценарий:
когда мы даемdocument
Добавленtouch
Когда вызывается обработчик события, если оно вызывается внутри обработчика одновременноevent.preventDefault()
, то браузер (Chrome 56+) выдаст предупреждение:Unable to preventDefault inside passive event listener due to target being treated as passive
Перевод этого предупреждения: не может давать пассивные (пассивные) прослушиватели событийpreventDefault
, так как он считается пассивным.
Что это обозначает? Не волнуйтесь, прежде всего, давайте посмотрим, что этоpassive event listener
.但是在这之前,我们还是得复习一下addEventListener
третий параметр.
Неизвестный третий параметр
когда мы используемaddEventListener
Когда мы обычно пишем это так:
target.addEventListener(event, handler)
Я полагаю, что есть и другие, которые используют более полный способ письма:
target.addEventListener(event, handler, false)
Да, я думаю, что многие люди уже знают, что,addEventListener
У метода есть третий параметр, и мы часто передаемfalse
как этот третий параметр. Но это то же самое, если мы не передаем его, потому что третий параметр по умолчанию равенfalse
, Вы чувствуете, что написали много неоправданного кода по неизвестным причинам, и все еще считаете себя очень строгим?
Ха-ха, так что мы должны посмотреть, что делает этот третий параметр.
При нормальной работе этот третий параметр представляет собой логическое значение, называемоеuseCapture
, то есть в дереве DOM, будет ли элемент, зарегистрированный в прослушивателе, получать событие до любого целевого объекта события под ним.
Мы знаем, что поток событий DOM (поток событий) состоит из трех этапов: этап захвата событий, этап в целевом этапе, этап всплытия событий. еслиuseCapture
Установить какfalse
, текущий объект eventTarget не получит событие на этапе захвата. По умолчанию в браузерах мы не запускаем обработчики связанных событий на этапе захвата.
Но я считаю, что есть еще много людей, которые не восприняли это всерьез.addEventListener
docs, третий параметр не обязательно должен быть логическим. Также это может быть объект, набор конфигураций.
{
capture: Boolean, // 表示`listener`会在该类型的事件捕获阶段传播到该`EventTarget`时触发
once: Boolean, // 表示`listener`在添加之后最多只调用一次。如果是`true`,`listener`会在其被调用之后自动移除
passive: Boolean, // 表示`listener`永远不会调用`preventDefault()`。如果`listener`仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告
}
Кроме вышеперечисленного, есть ещеmozSystemGroup
, мы не будем обсуждать это сейчас.
Так что мы можем на самом делеuseCapture
На основе настройте два дополнительных элемента конфигурации.
once
выражатьlistener
Вызывается не более одного раза после добавления. еслиtrue
,listener
будет автоматически удален после его вызова, что похоже на то, что мы делали в эпоху jQuery.once
Метод аналогичен.
passive
выражатьlistener
никогда не звониpreventDefault()
. еслиlistener
Все еще вызывая эту функцию, клиент проигнорирует ее и выдаст консольное предупреждение. В частности, мы обсудим это позже.
passive event listener
в конкретных дискуссияхpassive event listener
Раньше мы сначала популяризировалиТочка знаний. Вы можете пойти и посмотреть английский документ самостоятельно, но вам нужно выйти в Интернет с научной точки зрения.
Короче говоря, когда мы прокручиваем страницу (обычно когда мы прослушиваем сенсорные события), страница фактически имеет короткую паузу (около 200 мс), и браузер не знает, хотим ли мы этого.preventDefault
, поэтому требуется задержка для обнаружения. Это привело к тому, что наше смахивание выглядело довольно запаздывающим.
Начиная с Chrome 51,passive event listener
Познакомившись с Chrome, мы можемaddEventListener
Настройка третьего параметра{ passive: true }
Чтобы браузер не обнаружил, вызвали ли мы его в обработчике события касанияpreventDefault
. В это время, если мы все еще звонимpreventDefault
, на консоль будет выведено предупреждение. скажи нам этоpreventDefault
будет игнорироваться.
когда мы даемaddEventListener
Третий параметр набора{ passive: true }
, этот прослушиватель событий называетсяpassive event listener.
Начиная с Chrome 56, если мы дадимdocument
связыватьtouchmove
илиtouchstart
прослушиватель событий, этоpassive
по умолчанию установлено значениеtrue
для повышения производительности, в частностидокументация по хромовой статуе. Но большинство из нас этого не знают и все равно звонятpreventDefault
. Это не приведет к ошибкам уровня сбоя страницы, но может привести к тому, что мы упустим момент оптимизации производительности страницы, особенно в мобильной части, где больше внимания уделяется оптимизации производительности.
совместимость
Третий параметр только недавно был настроен на набор элементов конфигурации.Если нам нужна совместимость со старыми браузерами, нам нужно написать код обнаружения.
var passiveSupported = false;
try {
var options = Object.defineProperty({}, "passive", {
get: function() {
passiveSupported = true;
}
});
window.addEventListener("test", null, options);
} catch(err) {}
Этот кодpassive
свойство создает функцию получения сoptions
объект; геттер устанавливает идентификатор,passiveSupported
, при вызове будет установлено значениеtrue
. Это означает, что если браузер проверяетoptions
на объектеpassive
ценность,passiveSupported
будет установлен наtrue
; иначе останетсяfalse
. Затем мы звонимaddEventListener()
Установить пустой обработчик событий, задающий эти параметры, чтобы значения параметров проверялись, если браузер считает третий параметр объектом.
Вы можете использовать этот метод для проверки любого значения параметров. Просто используйте код, аналогичный приведенному выше, с геттером для опции. Затем, когда вы действительно хотите создать прослушиватель событий, который поддерживает параметры или нет, вы можете сделать:
someElement.addEventListener("mouseup", handleMouseUp, passiveSupported ? { passive: true } : false);
мы вsomeElement
Мышь добавлена здесь. Для третьего параметра, еслиpassiveSupported
даtrue
, мы проходимpassive
значениеtrue
изoptions
объект; в противном случае мы знаем, что хотим передать логическое значение, поэтому мы передаемfalse
в видеuseCapture
параметр.
PS: В первый PR бага vue-carousel будуaddEventListener
изpassive
установлен вfalse
, но на самом деле это не оптимальное решение, оптимальным решением должно быть удаление слушателяpreventDefault
, я поднял еще один PR, чтобы исправить это.
Ссылаться на: