В настоящее время в моем модальном окне я реализую захват фокуса в целях доступности. Моя ловушка фокуса не позволит пользователю нажимать вкладку за пределами модального окна - если он нажимает вкладку на последнем элементе, он фокусируется на первом, а сдвиг табуляции на первом - на последнем. Вот где моя проблема была впервые замечена.
В моем функциональном компоненте модального окна есть useEffect. Этот useEffect определит внесение изменений и вызовет повторный рендеринг (с использованием специального перехватчика), а затем получит ссылку на все интерактивные элементы. Затем это передается в функцию focusTrap.
Пользовательский хук useIsMount (используется для проверки того, находится ли DOM при первом или втором рендеринге, в случае, если элементы не готовы к использованию):
Код: Выделить всё
export const useIsMount = () => {
const isMountRef = useRef(true);
useEffect(() => {
isMountRef.current = false;
}, []);
return isMountRef.current;
};
Код: Выделить всё
useEffectКод: Выделить всё
const isMount = useIsMount();
useEffect(() => {
if (!isMount) {
const buttonsElement = buttonsRef?.current;
buttonsElement && focusTrap(buttonsElement, onClose);
}
});
Код: Выделить всё
!isMountМоя функция focusTrap, которая до сих пор меня не подводила:
Код: Выделить всё
export const focusTrap = (modalElement, onClose) => {
const focusableElements = modalElement.querySelectorAll(
'button, [href], input, checkbox, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
const handleTabKeyPress = (event) => {
if (event.key === "Tab") {
if (event.shiftKey && document.activeElement === firstElement) {
event.preventDefault();
lastElement.focus();
} else if (!event.shiftKey && document.activeElement === lastElement) {
event.preventDefault();
firstElement.focus();
}
}
};
const handleEscapeKeyPress = (event) => {
if (event.key === "Escape") {
onClose();
}
};
modalElement.addEventListener("keydown", handleTabKeyPress, true);
modalElement.addEventListener("keydown", handleEscapeKeyPress);
return () => {
modalElement.removeEventListener("keydown", handleTabKeyPress, true);
modalElement.removeEventListener("keydown", handleEscapeKeyPress);
};
};

Я пробовал:
- Добавление пустого массив зависимостей (не улавливает повторную отрисовку изменения содержимого, не обнаруживает кнопку «Загрузить»)
- Добавление массива зависимостей для isMount и totalEdits/(отслеживайте объемы редактирования/удаления для отображения кнопки «Загрузить»), но я все равно вызываю focusTrap, поскольку мне нужен оператор if, чтобы определить, есть ли изменения
Код: Выделить всё
totalDeletesКод: Выделить всё
if (totalEdits > 0 || totalDeletes > 0) { buttonsElement && focusTrap(buttonsElement, onClose); } - Куча других вещей, которые я, честно говоря, даже не могу сейчас вспомнить. Либо ловушка фокуса выйдет из модального окна (но обнаружит новую кнопку!), либо кнопка все еще не фокусируется.
Можно ли каким-то образом завершить работу функции, прежде чем она запустится снова?
Наконец, если я условно визуализирую эту кнопку где-то, что она не является последним элементом, она фокусируется нормально (как перед кнопкой «Подтвердить»). Однако focusTrap по-прежнему запускается несколько раз, и это нехорошо.
Подробнее здесь: https://stackoverflow.com/questions/798 ... -if-statem
Мобильная версия