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?

6voto

Ally Punkte 4536

Hier ist meine Lösung. Es wird funktionieren, wenn ein Element innerhalb eines scrollbaren Containers ausgeblendet wird.

Hier ist eine Demo (versuchen Sie, die Größe des Fensters zu ändern)

var visibleY = function(el){
    var top = el.getBoundingClientRect().top, rect, el = el.parentNode;
    do {
        rect = el.getBoundingClientRect();
        if (top <= rect.bottom === false)
            return false;
        el = el.parentNode;
    } while (el != document.body);
    // Check it's within the document viewport
    return top <= document.documentElement.clientHeight;
};

Ich musste nur prüfen, ob er auf der Y-Achse sichtbar ist (für eine Ajax-Funktion zum Laden weiterer Datensätze mit Bildlauf).

5voto

Dakusan Punkte 6255

Die meisten akzeptierten Antworten funktionieren nicht beim Zoomen in Google Chrome auf Android. In Kombination mit Dans Antwort , um Chrome auf Android zu berücksichtigen, visualViewport verwendet werden muss. Das folgende Beispiel berücksichtigt nur die vertikale Prüfung und verwendet jQuery für die Fensterhöhe:

var Rect = YOUR_ELEMENT.getBoundingClientRect();
var ElTop = Rect.top, ElBottom = Rect.bottom;
var WindowHeight = $(window).height();
if(window.visualViewport) {
    ElTop -= window.visualViewport.offsetTop;
    ElBottom -= window.visualViewport.offsetTop;
    WindowHeight = window.visualViewport.height;
}
var WithinScreen = (ElTop >= 0 && ElBottom <= WindowHeight);

4voto

Pirijan Punkte 3122

Basierend auf Dans Lösung Ich habe versucht, die Implementierung zu bereinigen, damit es einfacher ist, sie mehrmals auf derselben Seite zu verwenden:

$(function() {

  $(window).on('load resize scroll', function() {
    addClassToElementInViewport($('.bug-icon'), 'animate-bug-icon');
    addClassToElementInViewport($('.another-thing'), 'animate-thing');
    //  repeat as needed ...
  });

  function addClassToElementInViewport(element, newClass) {
    if (inViewport(element)) {
      element.addClass(newClass);
    }
  }

  function inViewport(element) {
    if (typeof jQuery === "function" && element instanceof jQuery) {
      element = element[0];
    }
    var elementBounds = element.getBoundingClientRect();
    return (
      elementBounds.top >= 0 &&
      elementBounds.left >= 0 &&
      elementBounds.bottom <= $(window).height() &&
      elementBounds.right <= $(window).width()
    );
  }

});

Die Art, wie ich es verwende ist, dass, wenn das Element in die Ansicht scrollt, ich bin eine Klasse hinzufügen, die eine CSS-Keyframe-Animation auslöst. Es ist ziemlich geradlinig und funktioniert besonders gut, wenn Sie wie 10+ Dinge auf einer Seite bedingt animieren haben.

0 Stimmen

Sie sollten auf jeden Fall cachen $window = $(window) außerhalb des Scroll-Handlers

4voto

Berker Yüceer Punkte 6616

Die meisten der in den vorherigen Antworten genannten Verwendungen scheitern an diesen Punkten:

-Wenn ein beliebiges Pixel eines Elements sichtbar ist, aber nicht " eine Ecke ",

-Wenn ein Element größer als das Ansichtsfenster und zentriert ,

-Die meisten von ihnen prüfen nur ein einzelnes Element innerhalb eines Dokuments oder Fensters .

Nun, für all diese Probleme habe ich eine Lösung, und das sind die Vorteile:

-Sie können zurückkehren visible wenn nur ein Pixel von irgendeiner Seite auftaucht und keine Ecke ist,

-Sie können noch zurückkehren visible wenn das Element größer als das Ansichtsfenster ist,

-Sie können Ihr parent element oder Sie können es automatisch auswählen lassen,

-Arbeiten an dynamisch hinzugefügte Elemente auch.

Anhand der nachstehenden Ausschnitte können Sie den Unterschied bei der Verwendung von overflow-scroll im Container des Elements wird keine Probleme verursachen und dafür sorgen, dass im Gegensatz zu anderen Antworten hier auch wenn ein Pixel aus beliebige Seite oder wenn ein Element größer ist als der Viewport und wir sehen innere Pixel des Elements es funktioniert immer noch.

Die Verwendung ist einfach:

// For checking element visibility from any sides
isVisible(element)

// For checking elements visibility in a parent you would like to check
var parent = document; // Assuming you check if 'element' inside 'document'
isVisible(element, parent)

// For checking elements visibility even if it's bigger than viewport
isVisible(element, null, true) // Without parent choice
isVisible(element, parent, true) // With parent choice

Eine Demonstration ohne crossSearchAlgorithm was für Elemente nützlich ist, die größer sind als der Viewport, überprüfen Sie die inneren Pixel von element3:

function isVisible(element, parent, crossSearchAlgorithm) {
    var rect = element.getBoundingClientRect(),
            prect = (parent != undefined) ? parent.getBoundingClientRect() : element.parentNode.getBoundingClientRect(),
        csa = (crossSearchAlgorithm != undefined) ? crossSearchAlgorithm : false,
        efp = function (x, y) { return document.elementFromPoint(x, y) };
    // Return false if it's not in the viewport
    if (rect.right < prect.left || rect.bottom < prect.top || rect.left > prect.right || rect.top > prect.bottom) {
        return false;
    }
    var flag = false;
    // Return true if left to right any border pixel reached
    for (var x = rect.left; x < rect.right; x++) {
        if (element.contains(efp(rect.top, x)) || element.contains(efp(rect.bottom, x))) {
        flag = true;
        break;
      }
    }
    // Return true if top to bottom any border pixel reached
    if (flag == false) {
      for (var y = rect.top; y < rect.bottom; y++) {
        if (element.contains(efp(rect.left, y)) || element.contains(efp(rect.right, y))) {
          flag = true;
          break;
        }
      }
    }
    if(csa) {
      // Another algorithm to check if element is centered and bigger than viewport
      if (flag == false) {
        var x = rect.left;
        var y = rect.top;
        // From top left to bottom right
        while(x < rect.right || y < rect.bottom) {
          if (element.contains(efp(x,y))) {
            flag = true;
            break;
          }
          if(x < rect.right) { x++; }
          if(y < rect.bottom) { y++; }
        }
        if (flag == false) {
          x = rect.right;
          y = rect.top;
          // From top right to bottom left
          while(x > rect.left || y < rect.bottom) {
            if (element.contains(efp(x,y))) {
              flag = true;
              break;
            }
            if(x > rect.left) { x--; }
            if(y < rect.bottom) { y++; }
          }
        }
      }
    }
    return flag;
}

// Check multiple elements visibility
document.getElementById('container').addEventListener("scroll", function() {
    var elementList = document.getElementsByClassName("element");
  var console = document.getElementById('console');
    for (var i=0; i < elementList.length; i++) {
      // I did not define parent, so it will be element's parent
    if (isVisible(elementList[i])) {
          console.innerHTML = "Element with id[" + elementList[i].id + "] is visible!";
      break;
    } else {
        console.innerHTML = "Element with id[" + elementList[i].id + "] is hidden!";
    }
  }
});

// Dynamically added elements
for(var i=4; i <= 6; i++) {
  var newElement = document.createElement("div");
  newElement.id = "element" + i;
  newElement.classList.add("element");
  document.getElementById('container').appendChild(newElement);
}

#console { background-color: yellow; }
#container {
  width: 300px;
  height: 100px;
  background-color: lightblue;
  overflow-y: auto;
  padding-top: 150px;
  margin: 45px;
}
.element {
  margin: 400px;
  width: 400px;
  height: 320px;
  background-color: green;
}
#element3 {
  position: relative;
  margin: 40px;
  width: 720px;
  height: 520px;
  background-color: green;
}
#element3::before {
  content: "";
  position: absolute;
  top: -10px;
  left: -10px;
  margin: 0px;
  width: 740px;
  height: 540px;
  border: 5px dotted green;
  background: transparent;
}

<div id="console"></div>
<div id="container">
    <div id="element1" class="element"></div>
    <div id="element2" class="element"></div>
    <div id="element3" class="element"></div>
</div>

Sie sehen, wenn Sie innerhalb des Elements3 kann nicht festgestellt werden, ob es sichtbar ist oder nicht, da wir nur prüfen, ob das Element von Seiten o Ecken .

Und diese beinhaltet crossSearchAlgorithm die es Ihnen ermöglicht, weiterhin visible wenn das Element größer als das Ansichtsfenster ist:

function isVisible(element, parent, crossSearchAlgorithm) {
    var rect = element.getBoundingClientRect(),
            prect = (parent != undefined) ? parent.getBoundingClientRect() : element.parentNode.getBoundingClientRect(),
        csa = (crossSearchAlgorithm != undefined) ? crossSearchAlgorithm : false,
        efp = function (x, y) { return document.elementFromPoint(x, y) };
    // Return false if it's not in the viewport
    if (rect.right < prect.left || rect.bottom < prect.top || rect.left > prect.right || rect.top > prect.bottom) {
        return false;
    }
    var flag = false;
    // Return true if left to right any border pixel reached
    for (var x = rect.left; x < rect.right; x++) {
        if (element.contains(efp(rect.top, x)) || element.contains(efp(rect.bottom, x))) {
        flag = true;
        break;
      }
    }
    // Return true if top to bottom any border pixel reached
    if (flag == false) {
      for (var y = rect.top; y < rect.bottom; y++) {
        if (element.contains(efp(rect.left, y)) || element.contains(efp(rect.right, y))) {
          flag = true;
          break;
        }
      }
    }
    if(csa) {
      // Another algorithm to check if element is centered and bigger than viewport
      if (flag == false) {
        var x = rect.left;
        var y = rect.top;
        // From top left to bottom right
        while(x < rect.right || y < rect.bottom) {
          if (element.contains(efp(x,y))) {
            flag = true;
            break;
          }
          if(x < rect.right) { x++; }
          if(y < rect.bottom) { y++; }
        }
        if (flag == false) {
          x = rect.right;
          y = rect.top;
          // From top right to bottom left
          while(x > rect.left || y < rect.bottom) {
            if (element.contains(efp(x,y))) {
              flag = true;
              break;
            }
            if(x > rect.left) { x--; }
            if(y < rect.bottom) { y++; }
          }
        }
      }
    }
    return flag;
}

// Check multiple elements visibility
document.getElementById('container').addEventListener("scroll", function() {
    var elementList = document.getElementsByClassName("element");
  var console = document.getElementById('console');
    for (var i=0; i < elementList.length; i++) {
      // I did not define parent so it will be element's parent
    // and it will do crossSearchAlgorithm
    if (isVisible(elementList[i],null,true)) {
          console.innerHTML = "Element with id[" + elementList[i].id + "] is visible!";
      break;
    } else {
        console.innerHTML = "Element with id[" + elementList[i].id + "] is hidden!";
    }
  }
});
// Dynamically added elements
for(var i=4; i <= 6; i++) {
  var newElement = document.createElement("div");
  newElement.id = "element" + i;
  newElement.classList.add("element");
  document.getElementById('container').appendChild(newElement);
}

#console { background-color: yellow; }
#container {
  width: 300px;
  height: 100px;
  background-color: lightblue;
  overflow-y: auto;
  padding-top: 150px;
  margin: 45px;
}
.element {
  margin: 400px;
  width: 400px;
  height: 320px;
  background-color: green;
}
#element3 {
  position: relative;
  margin: 40px;
  width: 720px;
  height: 520px;
  background-color: green;
}
#element3::before {
  content: "";
  position: absolute;
  top: -10px;
  left: -10px;
  margin: 0px;
  width: 740px;
  height: 540px;
  border: 5px dotted green;
  background: transparent;
}

<div id="console"></div>
<div id="container">
    <div id="element1" class="element"></div>
    <div id="element2" class="element"></div>
    <div id="element3" class="element"></div>
</div>

JSFiddle zum Mitspielen: http://jsfiddle.net/BerkerYuceer/grk5az2c/

Dieser Code ist für genauere Informationen darüber gedacht, ob ein Teil des Elements in der Ansicht angezeigt wird oder nicht. Für Leistungsoptionen oder nur vertikale Dias sollten Sie diesen Code nicht verwenden! Dieser Code ist in Zeichnungsfällen effektiver.

2voto

www139 Punkte 4461

Ich hatte die gleiche Frage und fand es heraus, indem ich getBoundingClientRect() verwendete.

Dieser Code ist völlig "generisch" und muss nur einmal geschrieben werden, damit er funktioniert (Sie müssen ihn nicht für jedes Element schreiben, von dem Sie wissen wollen, dass es sich im Ansichtsfenster befindet).

Dieser Code prüft nur, ob er sich vertikal im Ansichtsfenster befindet, nicht waagerecht . In diesem Fall enthält die Variable (Array) "elements" alle Elemente, bei denen Sie prüfen, ob sie sich vertikal im Ansichtsfenster befinden, also greifen Sie sich beliebige Elemente, die Sie irgendwo haben wollen, und speichern Sie sie dort.

Die "for-Schleife" durchläuft jedes Element und prüft, ob es sich vertikal im Ansichtsfenster befindet. Dieser Code führt aus jedes Mal der Benutzer scrollt! Wenn getBoudingClientRect().top weniger als 3/4 des Viewports beträgt (das Element befindet sich zu einem Viertel im Viewport), wird es als "im Viewport" registriert.

Da der Code generisch ist, müssen Sie wissen, welches Element sich im Ansichtsfenster befindet. Um das herauszufinden, können Sie es über ein benutzerdefiniertes Attribut, den Knotennamen, die ID, den Klassennamen und mehr bestimmen.

Hier ist mein Code (sagen Sie mir, wenn er nicht funktioniert; er wurde in Internet Explorer 11, Firefox 40.0.3, Chrome Version 45.0.2454.85 m, Opera 31.0.1889.174 und Edge mit Windows 10 getestet, [noch nicht Safari])...

// Scrolling handlers...
window.onscroll = function(){
  var elements = document.getElementById('whatever').getElementsByClassName('whatever');
  for(var i = 0; i != elements.length; i++)
  {
   if(elements[i].getBoundingClientRect().top <= window.innerHeight*0.75 &&
      elements[i].getBoundingClientRect().top > 0)
   {
      console.log(elements[i].nodeName + ' ' +
                  elements[i].className + ' ' +
                  elements[i].id +
                  ' is in the viewport; proceed with whatever code you want to do here.');
   }
};

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