Start · Sprachen · JavaScript · Referenz · Highlight.forEach()

Highlight.forEach()

Methode

Führt eine Callback-Funktion einmal für jedes <code>AbstractRange</code>-Objekt eines <code>Highlight</code> aus, und zwar in der Reihenfolge, in der die Bereiche eingefügt wurden.

seit JavaScript CSS Custom Highlight API – Chrome/Edge 105+, Safar Kategorie: webapi

Signatur

Highlight.prototype.forEach(callbackFn, thisArg)

Beschreibung

Highlight gehört zur CSS Custom Highlight API und verhält sich wie ein Set aus Range- bzw. StaticRange-Objekten. Deshalb arbeitet forEach() genauso wie Set.prototype.forEach(): Der Callback läuft für jeden Bereich einmal, in der Reihenfolge, in der die Bereiche hinzugefügt wurden.

Die Methode eignet sich, um alle Bereiche eines Highlights auszuwerten oder zu prüfen – zum Beispiel, um den markierten Text auszulesen, Treffer einer Suche zu zählen oder vor dem Entfernen zu protokollieren, welche Bereiche noch hervorgehoben sind.

Wie bei Set bekommt der Callback den Wert zweimal übergeben (als value und als key). Das hält die Schnittstelle einheitlich mit Map.prototype.forEach(). Wenn du Ergebnisse zurückgeben oder die Schleife vorzeitig abbrechen willst, nimm lieber for...of oder Array.from(highlight).

Parameter

Name Typ Default Beschreibung
$callbackFn Pflicht (value: AbstractRange, key: AbstractRange, highlight: Highlight) => void Funktion, die für jeden Bereich aufgerufen wird. Sie erhält value (den aktuellen Bereich), key (denselben Bereich noch einmal, wie bei Set) und highlight (das Highlight, auf dem forEach() aufgerufen wurde).
$thisArg any undefined Wert, der beim Ausführen von callbackFn als this gilt. Bei Pfeilfunktionen hat er keine Wirkung.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. forEach() lässt sich nicht verketten.

Beispiele

Highlight anlegen und alle Bereiche ausgeben

// HTML: <p id="text">JavaScript ist vielseitig und JavaScript ist schnell.</p>
const textNode = document.getElementById('text').firstChild;

const r1 = new Range();
r1.setStart(textNode, 0);
r1.setEnd(textNode, 10);

const r2 = new Range();
r2.setStart(textNode, 27);
r2.setEnd(textNode, 37);

const highlight = new Highlight(r1, r2);
CSS.highlights.set('treffer', highlight);

highlight.forEach((range, key, set) => {
  console.log(`"${range.toString()}"`, range === key, set === highlight);
});
"JavaScript" true true "JavaScript" true true

Suchtreffer hervorheben und mit forEach auswerten

// CSS: ::highlight(suche) { background: yellow; }
const markiereBegriff = (root, begriff) => {
  const highlight = new Highlight();
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
  let node;
  while ((node = walker.nextNode())) {
    const text = node.textContent.toLowerCase();
    let idx = text.indexOf(begriff.toLowerCase());
    while (idx !== -1) {
      const range = new Range();
      range.setStart(node, idx);
      range.setEnd(node, idx + begriff.length);
      highlight.add(range);
      idx = text.indexOf(begriff.toLowerCase(), idx + begriff.length);
    }
  }
  CSS.highlights.set('suche', highlight);
  return highlight;
};

const hl = markiereBegriff(document.body, 'api');
let nr = 0;
hl.forEach((range) => {
  nr += 1;
  console.log(`Treffer ${nr} in <${range.startContainer.parentElement.tagName.toLowerCase()}>`);
});
console.log(`Gesamt: ${hl.size}`);
Treffer 1 in <h1> Treffer 2 in <p> Gesamt: 2

thisArg nutzen, um Ergebnisse zu sammeln

const highlight = new Highlight();
const p = document.createElement('p');
p.textContent = 'Hallo Welt';
document.body.append(p);

const r = new Range();
r.selectNodeContents(p);
highlight.add(r);

const sammler = { texte: [] };
highlight.forEach(function (range) {
  this.texte.push(range.toString());
}, sammler);

console.log(sammler.texte);
["Hallo Welt"]

// Wichtig · Fallstricke

  • Kein Abbruch möglich: return im Callback springt nur zum nächsten Bereich weiter. Um vorzeitig abzubrechen, nimm for (const range of highlight) mit break.
  • Ändern während der Schleife: Das Verhalten entspricht dem von Set. Bereiche, die während des Durchlaufs mit add() hinzukommen, werden noch besucht. Bereiche, die vor ihrem Aufruf mit delete() entfernt werden, werden übersprungen.
  • Bereiche ändern sich mit dem DOM: Ein normaler Range passt sich an, wenn sich das DOM ändert. Ein StaticRange tut das nicht und kann danach auf ungültige Stellen zeigen. Prüfe deshalb im Callback, ob ein Bereich noch gültig ist, zum Beispiel mit range.collapsed.
  • Browser-Unterstützung: Die CSS Custom Highlight API gibt es in Chromium ab Version 105 und in Safari ab 17.2. In Firefox ist sie erst in neueren Versionen verfügbar. Frage die Unterstützung vorher ab, etwa mit if ('highlights' in CSS).
  • Ein Highlight wird erst sichtbar, wenn es mit CSS.highlights.set() registriert und über ::highlight(name) gestaltet wurde. Für forEach() selbst ist die Registrierung nicht nötig.