Я ищу способ определить, произошло ли событие щелчка за пределами компонента, как описано в этой статье . jQuery closest () используется, чтобы увидеть, имеет ли цель из события click элемент dom в качестве одного из его родителей. В случае совпадения событие click принадлежит одному из дочерних элементов и, следовательно, не считается находящимся вне компонента.
Поэтому в моем компоненте я хочу прикрепить обработчик кликов к окну. Когда обработчик срабатывает, мне нужно сравнить цель с дочерними элементами моего компонента.
Событие click содержит такие свойства, как «путь», который, по-видимому, содержит исходный путь, по которому прошло событие. Я не уверен, что сравнивать или как лучше всего обойти это, и я думаю, что кто-то, должно быть, уже поместил это в умную функцию полезности ... Нет?
источник
Ответы:
Использование ссылок в React 16.3+ изменено.
Следующее решение использует ES6 и следует рекомендациям для привязки, а также для установки ссылки с помощью метода.
Чтобы увидеть это в действии:
Реализация класса:
Реализация крючков:
источник
document.addEventListener
здесь?context
необходим только в качестве аргумента в конструкторе, если он используется. Это не используется в этом случае. Причина, по которой группа реагирования рекомендует использоватьprops
в качестве аргумента конструктор, заключается в том, что использованиеthis.props
перед вызовомsuper(props)
будет неопределенным и может привести к ошибкам.context
все еще доступен на внутренних узлах, вот и вся цельcontext
. Таким образом, вам не нужно передавать его от компонента к компоненту, как это происходит с реквизитом. 2. Это всего лишь стилистическое предпочтение, и в данном случае оно не требует обсуждения.Вот решение, которое лучше всего сработало для меня без привязки событий к контейнеру:
Некоторые элементы HTML могут иметь так называемый « фокус », например, элементы ввода. Эти элементы также будут реагировать на событие размытия , когда они теряют фокус.
Чтобы дать любому элементу возможность фокусироваться, просто убедитесь, что его атрибут tabindex имеет значение, отличное от -1. В обычном HTML это было бы путем установки
tabindex
атрибута, но в React вы должны использоватьtabIndex
(обратите внимание на заглавнуюI
).Вы также можете сделать это через JavaScript с
element.setAttribute('tabindex',0)
Это то, для чего я его использовал, чтобы создать собственное меню DropDown.
источник
display:absolute
таков, что выпадающий не повлияет на размер родительского div. Это означает, что когда я щелкаю по элементу в раскрывающемся списке, срабатывает onblur.onBlur
сработают на вашем выпадающем контейнере иexpanded
будут установлены в false.Я застрял на том же вопросе. Я немного опоздал на вечеринку здесь, но для меня это действительно хорошее решение. Надеюсь, это поможет кому-то еще. Вам нужно импортировать
findDOMNode
изreact-dom
Реактивный подход крючков (16.8 +)
Вы можете создать многоразовый хук под названием
useComponentVisible
.Затем в компонент вы хотите добавить функциональность, чтобы сделать следующее:
Найдите пример кода и коробки здесь.
источник
ReactDOM.findDOMNode
и является устаревшим, следует использоватьref
обратные вызовы: github.com/yannickcr/eslint-plugin-react/issues/...Перепробовав здесь много методов, я решил использовать github.com/Pomax/react-onclickoutside из-за его завершенности.
Я установил модуль через npm и импортировал его в свой компонент:
Затем в своем классе компонентов я определил
handleClickOutside
метод:И при экспорте моего компонента я завернул его в
onClickOutside()
:Вот и все.
источник
tabIndex
/onBlur
подходом, предложенным Пабло ? Как работает реализация и как ее поведение отличается отonBlur
подхода?tabIndex/onBlur
подход. Он не работает, когда выпадающий списокposition:absolute
, например, меню над другим содержимым.Я нашел решение, благодаря Бену Альперту, на сайте обсуждения.reactjs.org . Предложенный подход прикрепляет обработчик к документу, но это оказалось проблематичным. Нажатие на один из компонентов в моем дереве привело к повторному отображению, при котором элемент обновления, по которому щелкнули, удалялся при обновлении. Поскольку повторное отображение из React происходит до вызова обработчика тела документа, элемент не был обнаружен как «внутри» дерева.
Решением этой проблемы было добавление обработчика в корневой элемент приложения.
главный:
составная часть:
источник
document
них не запущен ?mousedown
вероятно, будет лучшим обработчиком, чемclick
здесь. В большинстве приложений поведение «закрытие меню за щелчком» происходит в тот момент, когда вы нажимаете кнопку мыши, а не при отпускании. Попробуйте, например, с помощью флагов Stack Overflow или общих диалоговых окон или с одним из выпадающих меню в верхней строке меню вашего браузера.ReactDOM.findDOMNode
и строкаref
устарели, следует использоватьref
обратные вызовы: github.com/yannickcr/eslint-plugin-react/issues/…document
Реализация хуков на основе прекрасного выступления Таннера Линсли на JSConf Hawaii 2020 :
useOuterClick
Hook APIРеализация
useOuterClick
использует изменяемые ссылки для создания скудного API дляClient
. Обратный вызов может быть установлен без необходимости запоминать его черезuseCallback
. Тело обратного вызова по-прежнему имеет доступ к самым последним реквизитам и состоянию (без устаревших значений закрытия).Примечание для пользователей iOS
iOS обрабатывает только определенные элементы как кликабельные. Чтобы обойти это поведение, выберите другого внешнего слушателя щелчка, чем
document
- ничего выше, включаяbody
. Например, вы можете добавить слушателя в корень Reactdiv
в приведенном выше примере и увеличить его высоту (height: 100vh
или аналогичную), чтобы ловить все внешние клики. Источники: quirksmode.org и этот ответисточник
@media (hover: none) and (pointer: coarse) { body { cursor:pointer } }
Добавление этого в мои глобальные стили, кажется, решило проблему.@supports (-webkit-overflow-scrolling: touch)
который нацелен только на IOS, хотя я не знаю больше, сколько! Я только что проверил, и это работает.Ни один из других ответов здесь не работал для меня. Я пытался скрыть всплывающее окно на размытие, но поскольку содержимое было абсолютно позиционировано, onBlur срабатывал даже при щелчке внутреннего содержимого.
Вот подход, который работал для меня:
Надеюсь это поможет.
источник
document
. Спасибо.[Update] Решение с React ^ 16.8 с использованием хуков
CodeSandbox
Решение с React ^ 16.3 :
CodeSandbox
источник
.contains is not a function
, это может быть связано с тем, что вы передаете<div>
ref
опору пользовательскому компоненту, вы можете взглянуть наReact.forwardRef
Вот мой подход (демо - https://jsfiddle.net/agymay93/4/ ):
Я создал специальный компонент с именем,
WatchClickOutside
и он может быть использован как (я предполагаю,JSX
синтаксис):Вот код
WatchClickOutside
компонента:источник
ref
является устаревшим, следует использоватьref
обратные вызовы: reactjs.org/docs/refs-and-the-dom.htmlНа это уже есть много ответов, но они не обращаются
e.stopPropagation()
и не позволяют нажимать на ссылки реакции вне элемента, который вы хотите закрыть.Из-за того, что React имеет свой собственный искусственный обработчик событий, вы не можете использовать документ в качестве базы для слушателей событий. Это необходимо сделать
e.stopPropagation()
до того, как React использует сам документ. Если вы используете, например,document.querySelector('body')
вместо. Вы можете предотвратить переход по ссылке Реакт. Ниже приведен пример того, как я реализую щелчок снаружи и близко.Это использует ES6 и React 16.3 .
источник
Для тех, кому нужно абсолютное позиционирование, я выбрал простой вариант - добавить компонент-оболочку, стилизованный так, чтобы покрыть всю страницу прозрачным фоном. Затем вы можете добавить onClick для этого элемента, чтобы закрыть ваш внутренний компонент.
Как и сейчас, если вы добавите обработчик кликов по контенту, событие также будет распространено на верхний элемент div и, следовательно, вызовет handlerOutsideClick. Если это не ваше желаемое поведение, просто остановите передачу событий в вашем обработчике.
`
источник
Чтобы расширить принятый ответ, сделанный Беном Бадом , если вы используете styled-компоненты, передача ссылок таким образом приведет к ошибке, такой как «this.wrapperRef.contains не является функцией».
Предлагаемое исправление в комментариях, чтобы обернуть стилизованный компонент с помощью div и передать туда ссылку, работает. Сказав это, в своих документах они уже объясняют причину этого и правильное использование ссылок внутри styled-components:
Вот так:
Затем вы можете получить к нему доступ непосредственно в функции handleClickOutside:
Это также относится к подходу "onBlur":
источник
Material-UI имеет небольшой компонент для решения этой проблемы: https://material-ui.com/components/click-away-listener/, который вы можете выбрать из списка. Он весит 1,5 КБ в сжатом виде, поддерживает мобильные устройства, IE 11 и порталы.
источник
Моя самая большая проблема со всеми остальными ответами - это необходимость фильтровать события кликов от корня / родителя вниз. Я обнаружил, что проще всего было просто установить элемент-брат с позицией: fixed, z-index 1 за выпадающим списком и обработать событие click для фиксированного элемента в том же компоненте. Сохраняет все централизованным для данного компонента.
Пример кода
источник
Событие
path[0]
- последний нажатый элементисточник
Я использовал этот модуль (у меня нет связи с автором)
Это хорошо сработало.
источник
"Support for the experimental syntax 'classProperties' isn't currently enabled"
это просто работает прямо из коробки. Для любого, кто пробует это решение, не забудьте стереть любой устаревший код, который вы, возможно, скопировали при попытке попробовать другие решения. например, добавление прослушивателей событий кажется конфликтующим с этим.Я сделал это частично, следуя этому и следуя официальным документам React по обработке ссылок, которые требуют реакции ^ 16.3. Это единственное, что сработало для меня, попробовав некоторые другие предложения здесь ...
источник
Пример со Стратегией
Мне нравятся предоставленные решения, которые используют для того же, создавая оболочку вокруг компонента.
Поскольку это скорее поведение, я подумал о стратегии и придумал следующее.
Я новичок в React, и мне нужно немного помочь, чтобы сохранить шаблон в случаях использования
Пожалуйста, просмотрите и скажите мне, что вы думаете.
ClickOutsideBehavior
Образец использования
Ноты
Я подумал о сохранении переданных
component
хуков жизненного цикла и переопределил их методами, аналогичными следующим:component
это компонент, переданный в конструкторClickOutsideBehavior
.Это удалит включить / отключить шаблон от пользователя этого поведения, но это выглядит не очень хорошо, хотя
источник
В моем случае DROPDOWN решение Бен Бада работало хорошо, но у меня была отдельная кнопка переключения с обработчиком onClick. Таким образом, логика внешнего нажатия противоречила переключателю кнопки onClick. Вот как я решил это, передав ссылку на кнопку:
источник
Если вы хотите использовать крошечный компонент (466 байт в сжатом виде), который уже существует для этой функции, вы можете проверить эту реакцию библиотеки .
Преимущество библиотеки в том, что она также позволяет обнаруживать щелчки вне компонента и внутри другого. Он также поддерживает обнаружение других типов событий.
источник
Если вы хотите использовать крошечный компонент (466 байт в сжатом виде), который уже существует для этой функции, вы можете проверить эту реакцию библиотеки . Он захватывает события вне реагирующего компонента или элемента jsx.
Преимущество библиотеки в том, что она также позволяет обнаруживать щелчки вне компонента и внутри другого. Он также поддерживает обнаружение других типов событий.
источник
Я знаю, что это старый вопрос, но я продолжаю сталкиваться с этим, и у меня было много проблем, чтобы понять это в простом формате. Так что, если это немного облегчит жизнь, используйте OutsideClickHandler от airbnb. Это самый простой плагин для выполнения этой задачи без написания собственного кода.
Пример:
источник
источник
Вы можете простой способ решить вашу проблему, я покажу вам:
....
это работает для меня, удачи;)
источник
Я нашел это из статьи ниже:
render () {return ({this.node = node;}}> Переключить Popover {this.state.popupVisible && (Я поповер!)}); }}
Вот отличная статья об этой проблеме: «Обрабатывать клики за пределами компонентов React» https://larsgraubner.com/handle-outside-clicks-react/
источник
Добавьте
onClick
обработчик в контейнер верхнего уровня и увеличивайте значение состояния всякий раз, когда пользователь щелкает внутри. Передайте это значение соответствующему компоненту, и всякий раз, когда значение изменяется, вы можете выполнять работу.В этом случае мы звоним
this.closeDropdown()
всякий раз, когдаclickCount
значение изменяется.В
incrementClickCount
метод срабатывает внутри.app
контейнера , но не.dropdown
потому , что мы используем ,event.stopPropagation()
чтобы предотвратить образование пузырьков события.Ваш код может выглядеть примерно так:
источник
Чтобы заставить решение «focus» работать с раскрывающимися списками прослушивателей событий, вы можете добавить их с событием onMouseDown вместо onClick . Таким образом, событие сработает, и после этого всплывающее окно закроется так:
источник
источник
import ReactDOM from 'react-dom';
Я сделал решение на все случаи жизни.
Вы должны использовать Компонент Высокого Порядка, чтобы обернуть компонент, который вы хотели бы прослушивать для кликов за его пределами.
В этом примере компонента есть только одна опора: «onClickedOutside», которая получает функцию.
источник
UseOnClickOutside Hook - Реакция 16.8 +
Создать общую функцию useOnOutsideClick
Тогда используйте крючок в любом функциональном компоненте.
Ссылка на демо
Частично вдохновлен ответом @ pau1fitzgerald.
источник