dynamiczny link <a> przykładowa funkcja . javascript
<a>
z pełnym zestawem opcji, w tym walidacją URL, atrybutami dostępności i bezpiecznymi ustawieniami rel
.document.createElement
, walidacja klasą URL
, automatyczne dodanie rel="noopener noreferrer"
dla linków zewnętrznych, możliwość podpięcia zdarzeń, obsługa atrybutów niestandardowych (data-*), tryb ES Modules / TypeScript-ready./**
* Dynamicznie tworzy link <a> i wstrzykuje go do kontenera w DOM.
* Zwraca referencję do utworzonego elementu.
*
* @param {Object} cfg – konfiguracja linku
* @param {string} cfg.href – adres URL (wymagany)
* @param {string} cfg.text – tekst widoczny (wymagany)
* @param {string} cfg.parentId – id kontenera (wymagany)
* @param {string} [cfg.target] – np. '_blank', '_self', itd.
* @param {string|string[]} [cfg.cls] – klasa / tablica klas CSS
* @param {Object} [cfg.events] – mapa {typZdarzenia: handler}
* @param {Object} [cfg.attrs] – dowolne dodatkowe atrybuty {nazwa: wartość}
* @returns {HTMLAnchorElement|null} – nowy element lub null przy błędzie
*/
export function createDynamicLink(cfg) {
const { href, text, parentId, target = '_self', cls = [], events = {}, attrs = {} } = cfg;
/* 1. Walidacja i bezpieczny parse URL */
let url;
try { url = new URL(href, window.location.origin); }
catch (_) { console.error(`Niepoprawny URL: ${href}`); return null; }
/* 2. Pobranie kontenera */
const parent = document.getElementById(parentId);
if (!parent) { console.error(`Brak kontenera #${parentId}`); return null; }
/* 3. Utworzenie elementu <a> */
const a = document.createElement('a');
a.href = url.href;
a.textContent = text;
a.target = target;
/* 4. Bezpieczeństwo dla linków zewnętrznych */
if (url.origin !== window.location.origin && target === '_blank') {
a.rel = 'noopener noreferrer';
}
/* 5. Klasy CSS */
(Array.isArray(cls) ? cls : [cls]).filter(Boolean).forEach(c => a.classList.add(c));
/* 6. Dodatkowe atrybuty (np. aria-, data-, download) */
Object.entries(attrs).forEach(([k, v]) => a.setAttribute(k, v));
/* 7. Obsługa zdarzeń */
Object.entries(events).forEach(([type, handler]) => a.addEventListener(type, handler));
/* 8. Wstrzyknięcie do DOM */
parent.appendChild(a);
return a;
}
/* Przykład użycia */
createDynamicLink({
href: 'https://pl.wikipedia.org',
text: 'Wikipedia',
parentId: 'links',
target: '_blank',
cls: ['btn','btn-primary'],
events: { click: () => console.log('Kliknięto Wikipedia') },
attrs: { 'aria-label': 'Otwórz Wikipedię', 'data-category': 'external' }
});
document.createElement
zamiast innerHTML
createElement
unika parsowania HTML jako łańcucha znaków, dzięki czemu redukuje ryzyko XSS oraz zapewnia pełną kontrolę nad atrybutami i zdarzeniami.URL()
wspierany przez wszystkie nowoczesne przeglądarki dokładnie sprawdza składnię oraz umożliwia proste rozdzielenie składników (origin, pathname, search).TypeError
, który przechwytujemy i logujemy.rel="noopener noreferrer"
zabezpiecza przed atakiem window.opener
i wyciekiem Referer.url.origin !== window.location.origin
pozwala odróżnić linki wewnętrzne i pominąć zbędne atrybuty.data-*
) dodajemy iterując po słowniku attrs
, co ułatwia rozbudowę bez modyfikacji sygnatury funkcji.onclick
stosujemy addEventListener
, co wspiera separację logiki od widoku i łatwiejsze usuwanie/listenery once
.HTMLAnchorElement
, export funkcji ułatwia import w bundlerach (Vite, Webpack).<x-dynamic-link>
), dzięki czemu link konfigurowany jest samym HTML-em (atrybuty → właściwości JS).<a>
deklaratywnie, ale w surowym JS wciąż stosuje się opisany tu schemat.script-src 'self'
.event.target.matches('a.dynamic')
.DocumentFragment
, a następnie jednorazowo podpiąć fragment do DOM – zmniejsza to liczbę reflow.aria-label
, role
, a przy linkach będących przyciskiem – semantycznie lepszy jest <button>
.rel
chroni użytkownika przed phishingiem i atakami typu tab-napping.innerHTML
.return
, nieużywane zmienne.Jest
lub Vitest
do testów jednostkowych (DOM w JSDOM)._blank
.unsafe-inline
zakazanym, funkcja pozostaje w 100 % kompatybilna.classList.add
dla SVG – dla HTML <a>
jest OK, ale jeżeli wspierasz IE, konieczne polyfill-e.URL()
wymaga protokołu; dla schematów niestandardowych (mailto:, tel:) trzeba rozważyć dopuszczenie wyjątków lub lokalną walidację regex.<T extends Record<string,string>>
do silniejszej typizacji atrybutów.DocumentFragment
vs pojedyncze appendChild
przy > 1000 linków.Przedstawiona funkcja createDynamicLink
zapewnia:
• bezpieczne i szybkie generowanie dynamicznych linków,
• walidację adresu, ochronę przed XSS/tab-napping,
• elastyczne API (klasy, zdarzenia, atrybuty niestandardowe),
• zgodność z aktualnymi trendami (ES Modules, CSP, A11y).
Można ją bezpośrednio użyć w projektach vanilla JS, wpiąć w Web Componenty lub przepisać do frameworku. Dzięki modularności i walidacji nadaje się zarówno do prostych stron, jak i aplikacji SPA/SSR.