1268 Stimmen

Wie kann ich feststellen, ob ein DOM-Element im aktuellen Ansichtsfenster sichtbar ist?

Gibt es eine effiziente Methode, um festzustellen, ob ein DOM-Element (in einem HTML-Dokument) derzeit sichtbar ist (erscheint in der Ansichtsfenster )?

(Die Frage bezieht sich auf Firefox.)

1 Stimmen

Es kommt darauf an, was Sie unter sichtbar verstehen. Wenn Sie meinen, dass es derzeit auf der Seite angezeigt wird, können Sie es anhand des y-Offsets des Elements und der aktuellen Bildlaufposition berechnen.

1 Stimmen

Ich habe hinzugefügt meine eigene Lösung die dieses Problem löst

1 Stimmen

Berücksichtigt eine dieser Lösungen den Z-Index eines Dom-Knotens und wie das die Sichtbarkeit speziell durch möglicherweise Ausblenden von Elementen mit einem niedrigeren Z-Index beeinflussen könnte?

1voto

Chris Pratt Punkte 219403

Bei allen Antworten hier geht es darum, ob das Element vollständig im Ansichtsfenster enthalten ist und nicht nur in irgendeiner Weise sichtbar ist. Wenn zum Beispiel nur die Hälfte eines Bildes am unteren Rand der Ansicht sichtbar ist, werden die Lösungen hier scheitern, da sie das als "außerhalb" betrachten.

Ich hatte einen Anwendungsfall, bei dem ich Lazy Loading über IntersectionObserver aber wegen der Animationen, die während des Einblendens auftreten, wollte ich keine Bilder beobachten, die bereits beim Laden der Seite überschneiden. Um dies zu tun, habe ich den folgenden Code verwendet:

const bounding = el.getBoundingClientRect();
const isVisible = (0 < bounding.top && bounding.top < (window.innerHeight || document.documentElement.clientHeight)) ||
        (0 < bounding.bottom && bounding.bottom < (window.innerHeight || document.documentElement.clientHeight));

Dabei wird im Wesentlichen geprüft, ob die obere oder untere Begrenzung unabhängig im Ansichtsfenster liegt. Das andere Ende kann außerhalb sein, aber solange ein Ende drin ist, ist es zumindest teilweise "sichtbar".

1voto

cryss Punkte 3830

Hier ist ein Schnipsel, um zu prüfen, ob das angegebene Element in seinem übergeordneten Element vollständig sichtbar ist:

export const visibleInParentViewport = (el) => {
  const elementRect = el.getBoundingClientRect();
  const parentRect = el.parentNode.getBoundingClientRect();

  return (
    elementRect.top >= parentRect.top &&
    elementRect.right >= parentRect.left &&
    elementRect.top + elementRect.height <= parentRect.bottom &&
    elementRect.left + elementRect.width <= parentRect.right
  );
}

0voto

Sander Jonk Punkte 27

Ich verwende diese Funktion (sie prüft nur, ob das y auf dem Bildschirm ist, da das x in den meisten Fällen nicht benötigt wird)

function elementInViewport(el) {
    var elinfo = {
        "top":el.offsetTop,
        "height":el.offsetHeight,
    };

    if (elinfo.top + elinfo.height < window.pageYOffset || elinfo.top > window.pageYOffset + window.innerHeight) {
        return false;
    } else {
        return true;
    }

}

-1voto

dirck Punkte 302

Domysee's Antwort https://stackoverflow.com/a/37998526 ist nahezu korrekt.

Viele Beispiele verwenden "vollständig im Ansichtsfenster enthalten", und sein Code verwendet Prozentsätze, um eine teilweise Sichtbarkeit zu ermöglichen. Sein Code geht auch auf die Frage ein, ob ein übergeordnetes Element die Ansicht beschneidet, was die meisten Beispiele ignorieren.

Ein fehlendes Element ist die Auswirkung der Bildlaufleisten des Elternteils - getBoundingClientRect gibt das äußere Rechteck des übergeordneten Elements zurück, das die Bildlaufleisten enthält, nicht das innere Rechteck, das dies nicht tut. Ein Kind kann sich hinter der übergeordneten Bildlaufleiste verstecken und als sichtbar gelten, obwohl es nicht sichtbar ist.

Das empfohlene Beobachtermuster ist für meinen Anwendungsfall nicht geeignet: die Verwendung der Pfeiltasten, um die aktuell ausgewählte Zeile in einer Tabelle zu ändern und sicherzustellen, dass die neue Auswahl sichtbar ist. Die Verwendung eines Beobachters für diesen Zweck wäre übermäßig kompliziert.

Hier ist etwas Code -

enthält er einen zusätzlichen Hack ( fudgeY ), da meine Tabelle eine klebrige Kopfzeile hat, die nicht auf einfache Weise erkannt werden kann (und eine automatische Handhabung wäre ziemlich mühsam). Außerdem werden Dezimalwerte (0 bis 1) anstelle von Prozentsätzen für den erforderlichen sichtbaren Anteil verwendet. (In meinem Fall brauche ich das volle y, und x ist nicht relevant).

function intersectRect(r1, r2) {
    var r = {};
    r.left = r1.left < r2.left ? r2.left : r1.left;
    r.top = r1.top < r2.top ? r2.top : r1.top;
    r.right = r1.right < r2.right ? r1.right : r2.right;
    r.bottom = r1.bottom < r2.bottom ? r1.bottom : r2.bottom;
    if (r.left < r.right && r.top < r.bottom)
        return r;
    return null;
}

function innerRect(e) {
    var b,r;
    b = e.getBoundingClientRect();
    r = {};
    r.left = b.left;
    r.top = b.top;
    r.right = b.left + e.clientWidth;
    r.bottom = b.top + e.clientHeight;
    return r;
}

function isViewable(e, fracX, fracY, fudgeY) {
    // ref https://stackoverflow.com/a/37998526
    // intersect all the rects and then check the result once
    // innerRect: mind the scroll bars
    // fudgeY: handle "sticky" thead in parent table.  Ugh.
    var r, pr, er;

    er = e.getBoundingClientRect();
    r = er;
    for (;;) {
        e = e.parentElement;
        if (!e)
            break;
        pr = innerRect(e);
        if (fudgeY)
            pr.top += fudgeY;
        r = intersectRect(r, pr);
        if (!r)
            return false;
    }

    if (fracX && ((r.right-r.left) / (er.right-er.left)) < (fracX-0.001))
        return false;
    if (fracY && ((r.bottom-r.top) / (er.bottom-er.top)) < (fracY-0.001))
        return false;
    return true;
}

-2voto

Philzen Punkte 3279

Eine ähnliche Herausforderung, die mir sehr gefallen hat dieser Kernpunkt die ein Polyfill für scrollIntoViewIfNeeded() .

Das gesamte Kung Fu, das für die Antwort benötigt wird, befindet sich in diesem Block:

var parent = this.parentNode,
    parentComputedStyle = window.getComputedStyle(parent, null),
    parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
    parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
    overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
    overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
    overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
    overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
    alignWithTop = overTop && !overBottom;

this bezieht sich auf das Element, von dem Sie wissen wollen, ob es z. B. ein Element ist, overTop o overBottom - Sie sollten einfach den Sinn verstehen...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X