React Academy · Lekcja

Tooltipy i menu rozwijane za pomocą portali

Używaj portali do renderowania tooltipów i menu rozwijanych poza kontenerami overflow-hidden

Lekcja 4 z 413 kroki

Tooltipy i menu rozwijane za pomocą portali to bezpłatna lekcja React Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej React Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs React Academy zawiera 4 lekcji w sumie.

Witamy

W tej lekcji zbudują Państwo komponenty podpowiedzi i menu rozwijanego, które korzystają z React Portals do renderowania w document.body, omijając ograniczenia overflow-hidden rodzica i kontekstu stosu z-index.

Problem z overflow

Podpowiedź pozycjonowana względem przycisku wyzwalającego zostanie przycięta, jeśli którykolwiek z elementów nadrzędnych ma `overflow: hidden` lub `overflow: scroll`. Przeniesienie podpowiedzi do document.body za pomocą portalu całkowicie rozwiązuje ten problem.

Strategia pozycjonowania

Aby poprawnie pozycjonować podpowiedź renderowaną za pomocą portalu, należy zmierzyć prostokąt obwiedni elementu wyzwalającego za pomocą `getBoundingClientRect()` i obliczyć współrzędne bezwzględne z uwzględnieniem pozycji przewijania.
const rect = triggerRef.current.getBoundingClientRect();
const top = rect.bottom + window.scrollY + 8;
const left = rect.left + window.scrollX;

Komponent podpowiedzi

Należy zbudować komponent Tooltip, który opakowuje children, przypisuje referencję do elementu wyzwalającego i renderuje za pomocą portalu pozycjonowane pudełko podpowiedzi po najechaniu kursorem.
function Tooltip({ content, children }) {
  const [visible, setVisible] = useState(false);
  const [pos, setPos] = useState({ top: 0, left: 0 });
  const ref = useRef();

  const show = () => {
    const r = ref.current.getBoundingClientRect();
    setPos({ top: r.bottom + window.scrollY + 4,
             left: r.left + window.scrollX });
    setVisible(true);
  };

  return (
    <span ref={ref} onMouseEnter={show} onMouseLeave={() => setVisible(false)}>
      {children}
      {visible && createPortal(
        <div style={{ position:'absolute', top: pos.top, left: pos.left }}
             className="tooltip">{content}</div>,
        document.body
      )}
    </span>
  );
}

Aktualizowanie pozycji podczas przewijania i zmiany rozmiaru

Jeśli użytkownik przewija stronę, gdy podpowiedź jest widoczna, jej pozycja staje się nieaktualna. Należy nasłuchiwać zdarzeń `scroll` i `resize`, aby ponownie obliczać pozycję lub zamykać podpowiedź.
useEffect(() => {
  if (!visible) return;
  const update = () => setVisible(false);
  window.addEventListener('scroll', update, true);
  window.addEventListener('resize', update);
  return () => {
    window.removeEventListener('scroll', update, true);
    window.removeEventListener('resize', update);
  };
}, [visible]);

Architektura menu rozwijanego

Menu rozwijane działa według tego samego wzorca co podpowiedź. Przycisk wyzwalający pokazuje lub ukrywa menu, menu jest renderowane za pomocą portalu, a procedura obsługi kliknięcia poza menu je zamyka.

Procedura obsługi kliknięcia poza elementem

Należy użyć nasłuchiwacza `mousedown` na `document`, aby wykrywać kliknięcia poza menu. Należy porównać cel kliknięcia z referencjami menu i elementu wyzwalającego, aby zdecydować, czy zamknąć menu.
useEffect(() => {
  if (!open) return;
  const handler = (e) => {
    if (!menuRef.current?.contains(e.target) &&
        !triggerRef.current?.contains(e.target)) {
      setOpen(false);
    }
  };
  document.addEventListener('mousedown', handler);
  return () => document.removeEventListener('mousedown', handler);
}, [open]);

Nawigacja klawiaturą w menu rozwijanych

Należy zaimplementować ArrowDown/ArrowUp do poruszania się między elementami menu, Enter do wyboru oraz Escape do zamykania. Indeks elementu z fokusem należy przechowywać w stanie, a na elementach menu programowo wywoływać `.focus()`.

Używanie biblioteki do pozycjonowania

W zastosowaniach produkcyjnych należy używać **@floating-ui/react** (wcześniej Popper.js). Biblioteka automatycznie obsługuje flip (zmianę położenia przy krawędziach obszaru widoku), shift (utrzymywanie podpowiedzi w obszarze widocznym) oraz pozycjonowanie strzałki.
import { useFloating, flip, shift } from '@floating-ui/react';

const { refs, floatingStyles } = useFloating({
  middleware: [flip(), shift()],
});

Dostępność: ARIA dla podpowiedzi

W przypadku podpowiedzi należy dodać `role='tooltip'` do elementu podpowiedzi oraz `aria-describedby` wskazujące identyfikator podpowiedzi na elemencie wyzwalającym. Dzięki temu czytniki ekranu mogą odczytać treść podpowiedzi.
<button aria-describedby="tip1">Hover me</button>
{visible && createPortal(
  <div id="tip1" role="tooltip">Helpful text</div>,
  document.body
)}

Szybkie sprawdzenie

Jak obliczyć prawidłową pozycję podpowiedzi renderowanej za pomocą portalu na ekranie?

Podsumowanie

Portale pozwalają podpowiedziom i listom rozwijanym wydostać się poza rodziców z `overflow-hidden`. Należy zmierzyć element wyzwalający za pomocą `getBoundingClientRect`, dodać przesunięcia przewijania przy pozycjonowaniu absolutnym, zamykać element po kliknięciu poza nim lub przewinięciu oraz dodać atrybuty ARIA zapewniające dostępność.

Ukończenie kursu

Gratulacje! Ukończono kurs **Portale i modale w React**. Mogą Państwo tworzyć teraz dostępne, prawidłowo pozycjonowane modale, podpowiedzi i listy rozwijane, które nie są ograniczane przez żadne reguły układania elementów CSS.
Bezpłatny start

Ucz się React dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
88
Lekcje
324

Często zadawane pytania

Czy lekcja „Tooltipy i menu rozwijane za pomocą portali” jest bezpłatna?

Tak — pełny tekst „Tooltipy i menu rozwijane za pomocą portali” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu React Academy, przejdź na CoddyKit PRO. Kurs React Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Tooltipy i menu rozwijane za pomocą portali”?

Używaj portali do renderowania tooltipów i menu rozwijanych poza kontenerami overflow-hidden Ćwiczysz React Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć React Academy?

Nie wymagamy żadnego doświadczenia. React Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Tooltipy i menu rozwijane za pomocą portali”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji React Academy?

Tak. Każda lekcja React Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Czym są React Portals?
  2. Budowanie komponentu modalnego za pomocą portali
  3. Obsługa fokusu i pułapek klawiatury w modalach
  4. Tooltipy i menu rozwijane za pomocą portali
← Powrót do React Academy