Вопрос или проблема
Я работаю с библиотекой PrimeReact, а именно с их компонентом <Accordion>
(см. https://primereact.org/accordion/). PrimeReact предоставляет <AccordionTab>
, который должен быть отрисован как дочерний элемент <Accordion>
. Каждый таб отображает кликабельный заголовок для открытия/закрытия таба, и элемент этого заголовка – это <a>
. Если я добавляю контент в заголовок (используя проп header
компонента <AccordionTab>
), то элементы в контенте (даже если это кнопки или ссылки) не кликабельны (их обработчики onClick
даже не срабатывают). Я хотел бы преодолеть это и также предотвратить стандартное поведение PrimeReact (т.е. открытие/закрытие таба), если нажать на дочернюю ссылку/кнопку.
Я пытался нацелиться на элемент headerAction
через проп pt
и переопределить его обработчик onClick
на пользовательский, который вызывает preventDefault()/stopPropagation()
, но это не дало результата.
const preventOpeningClosingIfAnotherLinkWasClicked = (evt: MouseEvent<HTMLAnchorElement, MouseEvent>) => {
if (!evt.currentTarget.closest(`.${headerClassName}`)) {
evt.preventDefault();
evt.stopPropagation();
}
};
const passThroughOptions = {
headerAction: { onClick: preventOpeningClosingIfAnotherLinkWasClicked }
};
return (
<AccordionTab className={headerClassName} pt={passThroughOptions} header={headerElement}>
{child.content}
</AccordionTab>
);
Вместо того чтобы рендерить <AccordionTab>
как прямого потомка <Accordion>
, я мог бы обернуть их в
position: relative
и сделать контент заголовка прямым потомком этого
position: absolute
для правильного позиционирования. Это эффективно отрисует контент как родителя элемента заголовка <a>
, что, как я полагаю, позволит ему захватывать события клика. Но это странное решение, которое может вызвать проблемы с компоновкой/стилизацией самих табов, и я предпочел бы избежать этого, если возможно.
Как я могу решить эту проблему?
Ответ или решение
Чтобы использовать компонент <Accordion>
из библиотеки PrimeReact для рендеринга ссылки в заголовке таба, вам нужно учитывать некоторые особенности поведения этого компонента. В частности, проблема заключается в том, что элементы внутри заголовка (например, кнопки или ссылки) не обрабатывают события клика, так как клик по заголовку по умолчанию открывает или закрывает соответствующий таб. Давайте рассмотрим, как можно решить данную проблему.
Подход к решению
Ваша задача заключается в том, чтобы задать поведение, при котором клик на ссылки или кнопки внутри заголовка не вызовет открытие или закрытие аккордеона. Для этого мы можем использовать метод, который будет предотвращать стандартное поведение при клике на определенные элементы.
Вот общий алгоритм решения:
-
Определение обработчика событий: Вам нужно создать обработчик клика, который будет проверять, был ли клик выполнен на вашей ссылке или кнопке, и, в зависимости от этого, будет предотвращать дальнейшую обработку события.
-
Передача обработчика в
headerAction
: Мы можем воспользоваться свойствомpt
(pass-through) для передачи нашего обработчика в объектheaderAction
компонента<AccordionTab>
. -
Структура кода: Приведем пример реализации этого подхода.
Пример кода
import React from 'react';
import { Accordion, AccordionTab } from 'primereact/accordion';
const HeaderWithLink = () => {
const headerClassName = "custom-header";
const preventOpeningClosingIfAnotherLinkWasClicked = (evt) => {
const target = evt.currentTarget;
// Проверяем, был ли клик выполнен на конкретных элементах
if (target.tagName !== 'A') {
evt.preventDefault();
evt.stopPropagation();
}
};
const passThroughOptions = {
headerAction: { onClick: preventOpeningClosingIfAnotherLinkWasClicked },
};
const headerElement = (
<div className={headerClassName}>
<a href="https://example.com" onClick={(e) => e.stopPropagation()} target="_blank" rel="noopener noreferrer">
Перейти на пример
</a>
<span>Заголовок аккордеона</span>
</div>
);
return (
<Accordion>
<AccordionTab className={headerClassName} pt={passThroughOptions} header={headerElement}>
<p>Содержимое аккордеона...</p>
</AccordionTab>
</Accordion>
);
};
export default HeaderWithLink;
Пояснение коду
-
Обработчик событий: Функция
preventOpeningClosingIfAnotherLinkWasClicked
проверяет, был ли клик выполнен на элементе ссылки. Если это не ссылка, то клик предотвращает открытие/закрытие таба. -
Свойство
pt
: Мы передаем объектpassThroughOptions
в качестве свойстваpt
для<AccordionTab>
, которое содержит обработчик клика. -
Структура заголовка: Заголовок состоит из ссылки и текстового элемента, которые будут правильно обрабатываться без вмешательства друг в друга.
Заключение
С помощью этого подхода вы сможете иметь в заголовке <AccordionTab>
кликабельные ссылки или кнопки, которые не будут мешать основному поведению аккордеона. Такой метод является более чистым решением в сравнении с использованием родительских div
с позиционированием, тем самым минимизируя потенциальные проблемы с макетом.
Эти рекомендации помогут вам успешно реализовать вашу задачу, сохраняя гибкость и адаптивность вашего интерфейса на основе PrimeReact.