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?

51voto

ryanve Punkte 46296

Siehe die Quelle von Randbereich , die die getBoundingClientRect . Es ist wie:

function inViewport (element) {
  if (!element) return false;
  if (1 !== element.nodeType) return false;

  var html = document.documentElement;
  var rect = element.getBoundingClientRect();

  return !!rect &&
    rect.bottom >= 0 &&
    rect.right >= 0 && 
    rect.left <= html.clientWidth &&
    rect.top <= html.clientHeight;
}

Sie gibt zurück true wenn cualquier Teil des Elements im Ansichtsfenster liegt.

42voto

Stefan Steiger Punkte 72861

Im Dienste der Öffentlichkeit:
Dan's Antwort mit den richtigen Berechnungen (Element kann > Fenster, vor allem auf Handy-Bildschirmen), und richtige jQuery-Tests, sowie das Hinzufügen von isElementPartiallyInViewport:

Im Übrigen, der Unterschied zwischen window.i

function isElementPartiallyInViewport(el)
{
    // Special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) 
        el = el[0];

    var rect = el.getBoundingClientRect();
    // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
    var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
    var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

    return (vertInView && horInView);
}

// http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
function isElementInViewport (el)
{
    // Special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) 
        el = el[0];

    var rect = el.getBoundingClientRect();
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    return (
           (rect.left >= 0)
        && (rect.top >= 0)
        && ((rect.left + rect.width) <= windowWidth)
        && ((rect.top + rect.height) <= windowHeight)
    );
}

function fnIsVis(ele)
{
    var inVpFull = isElementInViewport(ele);
    var inVpPartial = isElementPartiallyInViewport(ele);
    console.clear();
    console.log("Fully in viewport: " + inVpFull);
    console.log("Partially in viewport: " + inVpPartial);
}

Testfall

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Test</title>
    <!--
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="scrollMonitor.js"></script>
    -->

    <script type="text/javascript">

        function isElementPartiallyInViewport(el)
        {
            // Special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) 
                el = el[0];

            var rect = el.getBoundingClientRect();
            // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
            var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
            var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

            return (vertInView && horInView);
        }

        // http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
        function isElementInViewport (el)
        {
            // Special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) 
                el = el[0];

            var rect = el.getBoundingClientRect();
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            return (
                   (rect.left >= 0)
                && (rect.top >= 0)
                && ((rect.left + rect.width) <= windowWidth)
                && ((rect.top + rect.height) <= windowHeight)
            );
        }

        function fnIsVis(ele)
        {
            var inVpFull = isElementInViewport(ele);
            var inVpPartial = isElementPartiallyInViewport(ele);
            console.clear();
            console.log("Fully in viewport: " + inVpFull);
            console.log("Partially in viewport: " + inVpPartial);
        }

        // var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft,
        // var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
    </script>
</head>

<body>
    <div style="display: block; width: 2000px; height: 10000px; background-color: green;">

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <div style="background-color: crimson; display: inline-block; width: 800px; height: 500px;" ></div>
        <div id="myele" onclick="fnIsVis(this);" style="display: inline-block; width: 100px; height: 100px; background-color: hotpink;">
        t
        </div>

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />
    </div>

    <!--
    <script type="text/javascript">

        var element = document.getElementById("myele");
        var watcher = scrollMonitor.create(element);

        watcher.lock();

        watcher.stateChange(function() {
            console.log("state changed");
            // $(element).toggleClass('fixed', this.isAboveViewport)
        });
    </script>
    -->
</body>
</html>

4 Stimmen

isElementPartiallyInViewport ist ebenfalls sehr nützlich. Gut gemacht.

0 Stimmen

For isElementInViewport(e) : Ihr Code lädt nicht einmal Bilder, Dieser ist korrekt : function isElementInViewport(e) { var t = e.getBoundingClientRect(); return t.top >= 0 && t.left >= 0 && t.bottom <= (window.innerHeight || document.documentElement.clientHeight) && t.right <= (window.innerWidth || document.documentElement.clientWidth) }

2 Stimmen

@Arun chauhan: Keiner meiner Codes lädt Bilder, also warum sollte er, und die Formel ist korrekt.

33voto

Eric Chen Punkte 3578

Meine kürzere und schnellere Version:

function isElementOutViewport(el){
    var rect = el.getBoundingClientRect();
    return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}

Und ein jsFiddle nach Bedarf: https://jsfiddle.net/on1g619L/1/

4 Stimmen

Meine Lösung sind mehr gierig und schneller, wenn Element haben jedes Pixel in Viewport, es ist wird false zurückgeben.

1 Stimmen

Ich mag es. Kurz und bündig. Sie könnten die Leerzeichen zwischen Funktionsname und Klammer und zwischen Klammer und Klammer in der ersten Zeile entfernen. Ich habe diese Leerzeichen nie gemocht. Vielleicht liegt es nur an meinem Texteditor, der alles farblich kodiert, so dass es trotzdem leicht zu lesen ist. function aaa(arg){statements} Ich weiß, dass das die Ausführung nicht beschleunigt, sondern eher unter Mining fällt.

1 Stimmen

Das ist buchstäblich das Gegenteil von dem, was in der Frage gefragt wurde: Warum darf es eine solche Lösung geben? Zumindest sollte die Antwort besagen, dass diese Funktion verwendet werden kann, um zu prüfen, ob sich das Element außerhalb des Ansichtsfensters befindet, und sich nicht nur auf den Funktionsnamen verlassen, um dies zu implizieren.

28voto

Randy Casburn Punkte 12977

Die neue Schnittpunkt Beobachter API geht auf diese Frage sehr direkt ein.

Für diese Lösung wird ein Polyfill benötigt, da Safari, Opera und Internet Explorer dies noch nicht unterstützen (das Polyfill ist in der Lösung enthalten).

Bei dieser Lösung gibt es einen Kasten außerhalb des Sichtfelds, der das Ziel (beobachtet) ist. Wenn es in den Sichtbereich kommt, ist die Schaltfläche oben in der Kopfzeile ausgeblendet. Sie wird eingeblendet, sobald der Kasten die Ansicht verlässt.

const buttonToHide = document.querySelector('button');

const hideWhenBoxInView = new IntersectionObserver((entries) => {
  if (entries[0].intersectionRatio <= 0) { // If not in view
    buttonToHide.style.display = "inherit";
  } else {
    buttonToHide.style.display = "none";
  }
});

hideWhenBoxInView.observe(document.getElementById('box'));

header {
  position: fixed;
  top: 0;
  width: 100vw;
  height: 30px;
  background-color: lightgreen;
}

.wrapper {
  position: relative;
  margin-top: 600px;
}

#box {
  position: relative;
  left: 175px;
  width: 150px;
  height: 135px;
  background-color: lightblue;
  border: 2px solid;
}

<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<header>
  <button>NAVIGATION BUTTON TO HIDE</button>
</header>
  <div class="wrapper">
    <div id="box">
    </div>
  </div>

3 Stimmen

Gute Umsetzung, und laut dem Link in diese Antwort es sollte Arbeit auf Safari durch Hinzufügen von <!DOCTYPE html> zum HTML

0 Stimmen

Beachten Sie, dass IntersectionObserver ist eine experimentelle Funktion (die sich in Zukunft ändern kann).

2 Stimmen

@KarthikChintala - es wird in allen Browsern außer IE unterstützt - und es ist auch ein Polyfill verfügbar.

26voto

leonheess Punkte 9691

Die einfachste Lösung als Unterstützung von Element.getBoundingClientRect() hat perfekt werden :

function isInView(el) {
  const box = el.getBoundingClientRect();
  return box.top < window.innerHeight && box.bottom >= 0;
}

0 Stimmen

Wie verhält sich das auf mobilen Browsern? Die meisten von ihnen sind fehlerhaft in Bezug auf Viewport, mit ihrer Kopfzeile gehen nach oben oder unten auf scrollen, und unterschiedliches Verhalten, wenn die Tastatur zeigt, je nachdem, ob es Android oder ios, etc.

0 Stimmen

@Kev Sollte gut funktionieren, je nachdem, wann Sie diese Methode aufrufen. Wenn du sie aufrufst und dann die Größe des Fensters änderst, könnte das Ergebnis natürlich nicht mehr korrekt sein. Sie könnten sie bei jedem Größenänderungsereignis aufrufen, je nachdem, welche Art von Funktionalität Sie wünschen. Sie können gerne eine separate Frage zu Ihrem speziellen Anwendungsfall stellen und mich hier anpingen.

0 Stimmen

In 99% der Fälle reicht das aus, vor allem, wenn man nur einen Fader oder etwas anderes starten oder stoppen muss und etwas CPU sparen will. Es sind die Entwickler, die die Geräte zu Tode orientieren, nicht die normalen Benutzer. $(window).on('scroll', function(){ if(isInView($('.fader').get(0))) {} else {} });

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