Jak sprawdzić, czy element jest widoczny po przewinięciu?

1169

Ładuję elementy przez AJAX. Niektóre z nich są widoczne tylko po przewinięciu strony.
Czy jest jakiś sposób, aby wiedzieć, czy element jest teraz w widocznej części strony?

yoavf
źródło
42
oznacza, że ​​chce, aby metoda wiedziała, czy dany element jest wyświetlany w oknie przeglądarki lub czy użytkownik musi przewinąć, aby go zobaczyć.
Romain Linsolas
1
Aby sprawdzić, czy element jest w pełni widoczny w kontenerze, wystarczy dodać dodatkowy parametr selektora i ponownie użyć dla niego kodu elem. Library.IsElementVisibleInContainer = function (elementSelector, containerSelector) { var containerViewTop = $(containerSelector).offset().top; var containerViewBottom = containerViewTop + $(containerSelector).height();
Lifes
1
Wszystkie odpowiedzi wyzwalają przepływ, więc może to być szyjka butelki. Krzyczysz, używając IntersectionObserver, jeśli jest obsługiwany. Będzie miał lepszą wydajność w nowoczesnych przeglądarkach,
jcubic

Odpowiedzi:

1258

To powinno załatwić sprawę:

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

Prosta funkcja narzędziowa Pozwala na wywołanie funkcji narzędziowej, która akceptuje poszukiwany element i jeśli chcesz, aby element był w pełni widoczny lub częściowo.

function Utils() {

}

Utils.prototype = {
    constructor: Utils,
    isElementInView: function (element, fullyInView) {
        var pageTop = $(window).scrollTop();
        var pageBottom = pageTop + $(window).height();
        var elementTop = $(element).offset().top;
        var elementBottom = elementTop + $(element).height();

        if (fullyInView === true) {
            return ((pageTop < elementTop) && (pageBottom > elementBottom));
        } else {
            return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
        }
    }
};

var Utils = new Utils();

Stosowanie

var isElementInView = Utils.isElementInView($('#flyout-left-container'), false);

if (isElementInView) {
    console.log('in view');
} else {
    console.log('out of view');
}
Scott Dowding
źródło
52
Zauważ, że działa to tylko wtedy, gdy dokument jest przewijanym elementem, tzn. Nie sprawdzasz widoczności jakiegoś elementu wewnątrz przewijanego panelu wewnętrznego.
Andrew B.,
8
jak dodać małe przesunięcie?
Jürgen Paul
5
Tylko pracował kiedy użyłem window.innerHeightzamiast
Christian Schnorr
2
Bo elemTopużyłem $(elem).position().topi elemBottomużyłem elemTop + $(elem).outerHeight(true).
Sarah Vessels
13
Dla: „Dowolnej części elementu w widoku” użyłem: (((elemTop> = docViewTop) i& (elemTop <= docViewBottom)) || ((elemBottom> = docViewTop) && (elemBottom <= docViewBottom)))
Grizly,
415

Ta odpowiedź w języku waniliowym:

function isScrolledIntoView(el) {
    var rect = el.getBoundingClientRect();
    var elemTop = rect.top;
    var elemBottom = rect.bottom;

    // Only completely visible elements return true:
    var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
    // Partially visible elements return true:
    //isVisible = elemTop < window.innerHeight && elemBottom >= 0;
    return isVisible;
}
brawur
źródło
27
nie powinno tak być isVisible = elementTop < window.innerHeight && elementBottom >= 0? W przeciwnym razie element w połowie ekranu zwraca wartość false.
gman
7
Nie. sprawdzam, czy jakiś element jest w pełni widoczny na stronie. jeśli chcesz sprawdzić widoczność jakiejś części - możesz dostosować ten fragment kodu.
bravedick
15
Uważam, że ta odpowiedź działa lepiej niż wybrana odpowiedź. Prostsze też.
Adam Venezia,
12
W porównaniu z zatwierdzoną odpowiedzią, działa znacznie lepiej z setkami elementów.
ncla,
5
zobacz małe skrzypce demonstrujące tutaj - jsfiddle.net/shaaraddalvi/4rp09jL0
upInCloud
122

Aktualizacja: użyj IntersectionObserver


Najlepszą metodą, jaką znalazłem do tej pory, jest wtyczka jQuery . Działa jak marzenie.

Naśladuje niestandardowe zdarzenie „pojawiania się”, które jest uruchamiane, gdy element przewija się do widoku lub w inny sposób staje się widoczny dla użytkownika.

$('#foo').appear(function() {
  $(this).text('Hello world');
});

Wtyczki tej można użyć, aby zapobiec niepotrzebnym żądaniom treści ukrytych lub znajdujących się poza widocznym obszarem.

Joe Lencioni
źródło
30
To bez wątpienia fajna wtyczka, ale nie odpowiada na pytanie.
Jon Adams
5
Chociaż wtyczka jQuery-pojawi się dobra dla zawartości w obszarze strony głównej, niestety ma problemy z przesuwaniem div div o stałym rozmiarze z przepełnieniem. Zdarzenie może zostać uruchomione przedwcześnie, gdy związany element znajdzie się w obszarze, który można wyświetlić na stronie, ale poza widocznym obszarem div, a następnie nie zostanie uruchomiony zgodnie z oczekiwaniami, gdy element pojawi się w div.
Peter,
17
Czy jest wtyczka znikająca?
Shamoon
3
@Shamoon sprawdź źródło appear plugini prawdopodobnie będziesz musiał po prostu dodać !gdzieś, aby uzyskać disappearwtyczkę.
Lucky Soni,
5
Uwaga: to nie działa z jQuery 1.11.X github.com/morr/jquery.appear/issues/37
Jason Parham
86

Oto moje czyste rozwiązanie JavaScript, które działa, jeśli jest również ukryte w przewijalnym pojemniku.

Demo tutaj (spróbuj również zmienić rozmiar okna)

var visibleY = function(el){
  var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height, 
    el = el.parentNode
  // Check if bottom of the element is off the page
  if (rect.bottom < 0) return false
  // Check its within the document viewport
  if (top > document.documentElement.clientHeight) return false
  do {
    rect = el.getBoundingClientRect()
    if (top <= rect.bottom === false) return false
    // Check if the element is out of view due to a container scrolling
    if ((top + height) <= rect.top) return false
    el = el.parentNode
  } while (el != document.body)
  return true
};

EDYCJA 26.03.2016: Zaktualizowałem rozwiązanie, aby uwzględnić przewijanie obok elementu, więc jest ono ukryte nad górną powierzchnią kontenera z możliwością przewijania. EDYCJA 2018-10-08: Zaktualizowano, aby obsługiwał po przewinięciu poza ekran nad ekranem.

Sprzymierzyć
źródło
dzięki, może lepiej być return top <= document.documentElement.clientHeight && top >= 0;
Yousef Salimpour
16
+1 To była jedyna zakodowana (tj. Nie trzecia) odpowiedź, która uwzględnia rekurencyjną naturę elementów. Rozszerzyłem obsługę przewijania w poziomie, w pionie i na stronie: jsfiddle.net/9nuqpgqa
Pebbl
3
To rozwiązanie sprawdza tylko górną część elementu. Jeśli pierwszy górny piksel jest widoczny, zwróci wartość true, nawet jeśli reszta elementu nie będzie widoczna. Aby sprawdzić, czy cały element jest widoczny, musisz również sprawdzić dolną właściwość.
Wojciech Jakubas,
2
Tak, fajnie! Używane, aby pomóc napisać tę odpowiedź (z uznaniem jako komentarz js).
Roamer-1888
Brak; po drugim „return false” w pętli
Michaił Ramendik
45

Korzystanie z IntersectionObserver API (macierzysty w nowoczesnych przeglądarkach)

Za pomocą obserwatora łatwo i skutecznie można ustalić, czy element jest widoczny w viewpor lub w dowolnym przewijalnym pojemniku .

scrollEliminuje się potrzebę dołączania zdarzenia i ręcznego sprawdzania wywołania zwrotnego zdarzenia, a zatem wydajność:

// this is the target which is observed
var target = document.querySelector('div');

// configure the intersection observer instance
var intersectionObserverOptions = {
  root: null,
  rootMargin: '150px',
  threshold: 1.0
}
    
var observer = new IntersectionObserver(onIntersection, intersectionObserverOptions);

// provide the observer with a target
observer.observe(target);

function onIntersection(entries){
  entries.forEach(entry => {
    console.clear();
    console.log(entry.intersectionRatio)
    target.classList.toggle('visible', entry.intersectionRatio > 0);
    
    // Are we in viewport?
    if (entry.intersectionRatio > 0) {
      // Stop watching 
      // observer.unobserve(entry.target);
    }
  });
}
.box{ width:100px; height:100px; background:red; margin:1000px; }
.box.visible{ background:green; }
Scroll both Vertically & Horizontally...
<div class='box'></div>


Wyświetl tabelę obsługi przeglądarek (nie obsługiwane w IE / Safari)

vsync
źródło
4
Dzięki! To działa dla mnie, a także działa w IE11 z github.com/w3c/IntersectionObserver
Matt Wilson
Zdecydowanie najlepsze rozwiązanie. Pracował w IE11 bez wypełniacza!
Fabian von Ellerts,
Pamiętaj, że ten STILL nie jest obsługiwany w iOS / macOS Safari, niestety. Upewnij się, aby sprawdzić problemy z perfem, jeśli zdecydujesz się na wypełnianie, to duża grupa użytkowników
Leland
@Leland - zależy od projektu. dla wszystkich moich projektów jest to grupa absolutnie 0 użytkowników. Nie buduję stron internetowych, ale system internetowy;)
vsync
próbuję uruchomić to w pętli na kilku elementach, ale to nie działa. Jakieś pomysły? W tej pętli dodaję element docelowy.
Sascha Grindau
42

Wtyczka jQuery Waypoints wygląda tutaj bardzo ładnie.

$('.entry').waypoint(function() {
   alert('You have scrolled to an entry.');
});

Istnieje kilka przykładów na stronie wtyczki .

Fedir RYKHTIK
źródło
3
Dla mnie to działało tylko z przesunięciem $('#my-div').waypoint(function() { console.log('Hello there!'); }, { offset: '100%' });
leymannx
21

Co powiesz na

function isInView(elem){
   return $(elem).offset().top - $(window).scrollTop() < $(elem).height() ;
}

Następnie możesz uruchomić cokolwiek zechcesz, gdy element będzie już widoczny

$(window).scroll(function(){
   if (isInView($('.classOfDivToCheck')))
      //fire whatever you what 
      dothis();
})

To mi odpowiada

webicy
źródło
1
To działa dla mnie, ale użyłem, pozornie bardziej kompletnej, funkcji isScrolledIntoView na stackoverflow.com/questions/487073/... :)
Meetai.com
3
Myślę, że powinno to być $ (okno) .scrollTop () <$ (elem) .offset (). Top + $ (elem) .height ();
Młody
Moja modyfikacja wyglądałaby następująco: `return $ (okno) .scrollTop () + $ (okno) .height ()> $ (elem) .offset (). Top + $ (elem) .height (); `
bubencode
15

WebResourcesDepot napisał skrypt do załadowania podczas przewijania, który używa jQuery jakiś czas temu. Tutaj możesz obejrzeć ich demo na żywo . Ich funkcjonalność była następująca:

$(window).scroll(function(){
  if  ($(window).scrollTop() == $(document).height() - $(window).height()){
    lastAddedLiveFunc();
  }
});

function lastAddedLiveFunc() { 
  $('div#lastPostsLoader').html('<img src="images/bigLoader.gif">');
  $.post("default.asp?action=getLastPosts&lastPostID="+$(".wrdLatest:last").attr("id"),
    function(data){
        if (data != "") {
          $(".wrdLatest:last").after(data);         
        }
      $('div#lastPostsLoader').empty();
    });
};
Sampson
źródło
15

Poprawiłem fajną funkcję Scotta Dowdinga dla mojego wymagania - służy do sprawdzenia, czy element właśnie przewinął się do ekranu, tj. Jego górna krawędź.

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
Snigdha Batra
źródło
12

Zwykła wanilia, aby sprawdzić, czy element ( el) jest widoczny w przewijalnej div ( holder)

function isElementVisible (el, holder) {
  holder = holder || document.body
  const { top, bottom, height } = el.getBoundingClientRect()
  const holderRect = holder.getBoundingClientRect()

  return top <= holderRect.top
    ? holderRect.top - top <= height
    : bottom - holderRect.bottom <= height
},

Użycie z jQuery:

var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);
Denis Matafonov
źródło
2
W erze aplikacji jednostronicowych coraz częściej sprawdza się, czy element jest widoczny w jakimś innym elemencie poza oknem . To dlatego otrzymuję moje poparcie.
H Dog
8

isScrolledIntoView jest bardzo potrzebną funkcją, więc wypróbowałem ją, działa dla elementów nie wyższych niż rzutnia, ale jeśli element jest większy niż rzutnia, to nie działa. Aby to naprawić, łatwo zmień warunek

return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));

do tego:

return (docViewBottom >= elemTop && docViewTop <= elemBottom);

Zobacz demo tutaj: http://jsfiddle.net/RRSmQ/

Robert
źródło
8

Większość odpowiedzi tutaj nie bierze pod uwagę, że element można również ukryć, ponieważ jest on przewijany poza pole div, nie tylko całej strony.

Aby skorzystać z tej możliwości, musisz po prostu sprawdzić, czy element znajduje się w granicach każdego z jego rodziców.

To rozwiązanie robi dokładnie to:

function(element, percentX, percentY){
    var tolerance = 0.01;   //needed because the rects returned by getBoundingClientRect provide the position up to 10 decimals
    if(percentX == null){
        percentX = 100;
    }
    if(percentY == null){
        percentY = 100;
    }

    var elementRect = element.getBoundingClientRect();
    var parentRects = [];

    while(element.parentElement != null){
        parentRects.push(element.parentElement.getBoundingClientRect());
        element = element.parentElement;
    }

    var visibleInAllParents = parentRects.every(function(parentRect){
        var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
        var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
        var visiblePercentageX = visiblePixelX / elementRect.width * 100;
        var visiblePercentageY = visiblePixelY / elementRect.height * 100;
        return visiblePercentageX + tolerance > percentX && visiblePercentageY + tolerance > percentY;
    });
    return visibleInAllParents;
};

Pozwala także określić, jaki procent ma być widoczny w każdym kierunku.
Nie obejmuje możliwości, że może być ukryty z powodu innych czynników, takich jakdisplay: hidden .

Powinno to działać we wszystkich głównych przeglądarkach, ponieważ używa tylko getBoundingClientRect. Osobiście przetestowałem to w Chrome i Internet Explorer 11.

Domysee
źródło
Dziękuję za ten kod. Zastanawiam się, jak dodałbyś detektor zdarzeń przy przewijaniu w tym przypadku, że masz wiele zagnieżdżonych przewijalnych elementów? Wygląda na to, że samo dodanie detektora do okna nie wystarczy, czy musimy przejść z powrotem do najwyższego rodzica, aby dodać detektora do każdego przewijanego kontenera?
mr1031011
@ mr1031011 Powinno być możliwe dodanie modułu obsługi do okna, a następnie sprawdzenie celu w celu zidentyfikowania przewijanego kontenera.
Domysee
tak, to nie działa z przykładem podanym przez @vanowm,
mr1031011
7
function isScrolledIntoView(elem) {
    var docViewTop = $(window).scrollTop(),
        docViewBottom = docViewTop + $(window).height(),
        elemTop = $(elem).offset().top,
     elemBottom = elemTop + $(elem).height();
   //Is more than half of the element visible
   return ((elemTop + ((elemBottom - elemTop)/2)) >= docViewTop && ((elemTop + ((elemBottom - elemTop)/2)) <= docViewBottom));
}
Pascal Gagneur
źródło
7

Oto inne rozwiązanie z http://web-profile.com.ua/

<script type="text/javascript">
$.fn.is_on_screen = function(){
    var win = $(window);
    var viewport = {
        top : win.scrollTop(),
        left : win.scrollLeft()
    };
    viewport.right = viewport.left + win.width();
    viewport.bottom = viewport.top + win.height();

    var bounds = this.offset();
    bounds.right = bounds.left + this.outerWidth();
    bounds.bottom = bounds.top + this.outerHeight();

    return (!(viewport.right < bounds.left || viewport.left > bounds.right ||    viewport.bottom < bounds.top || viewport.top > bounds.bottom));
 };

if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('<div class="alert alert-success">target element is visible on screen</div>'); // log info       
    } else {
        $('.log').html('<div class="alert">target element is not visible on screen</div>'); // log info
    }
}
$(window).scroll(function(){ // bind window scroll event
if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('<div class="alert alert-success">target element is visible on screen</div>'); // log info
    } else {
        $('.log').html('<div class="alert">target element is not visible on screen</div>'); // log info
    }
}
});
</script>

Zobacz to w JSFiddle

Adrian P.
źródło
7

Dotyczy to każdego wypełnienia, granicy lub marginesu elementu, a także elementów większych niż sama rzutnia.

function inViewport($ele) {
    var lBound = $(window).scrollTop(),
        uBound = lBound + $(window).height(),
        top = $ele.offset().top,
        bottom = top + $ele.outerHeight(true);

    return (top > lBound && top < uBound)
        || (bottom > lBound && bottom < uBound)
        || (lBound >= top && lBound <= bottom)
        || (uBound >= top && uBound <= bottom);
}

Aby to nazwać, użyj czegoś takiego:

var $myElement = $('#my-element'),
    canUserSeeIt = inViewport($myElement);

console.log(canUserSeeIt); // true, if element is visible; false otherwise
Brent Barbata
źródło
7

Istnieje wtyczka dla jQuery o nazwie inview, która dodaje nowe zdarzenie „inview”.


Oto kod wtyczki jQuery, która nie używa zdarzeń:

$.extend($.expr[':'],{
    inView: function(a) {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
            ot = $(a).offset().top,
            wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();
        return ot > st && ($(a).height() + ot) < (st + wh);
    }
});

(function( $ ) {
    $.fn.inView = function() {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
        ot = $(this).offset().top,
        wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();

        return ot > st && ($(this).height() + ot) < (st + wh);
    };
})( jQuery );

Znalazłem to w komentarzu tutaj ( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ ) przez faceta o imieniu James

ness-EE
źródło
Niestety, przegląd jQuery nie jest już obsługiwany i nie działa z bieżącymi wersjami jQuery.
mikemaccana,
1
JQuery 1 obsługuje
starszą
Link nie pokazuje przykładu, ponieważ strona została zaktualizowana.
Profesor programowania
6

Musiałem sprawdzić widoczność elementów wewnątrz przewijanego pojemnika DIV

    //p = DIV container scrollable
    //e = element
    function visible_in_container(p, e) {
        var z = p.getBoundingClientRect();
        var r = e.getBoundingClientRect();

        // Check style visiblilty and off-limits
        return e.style.opacity > 0 && e.style.display !== 'none' &&
               e.style.visibility !== 'hidden' &&
               !(r.top > z.bottom || r.bottom < z.top ||
                 r.left > z.right || r.right < z.left);
    }
Pigmalión
źródło
to działa na mnie, gdybym zmienić e.style.opacity > 0się (!e.style.opacity || e.style.opacity > 0), ponieważ domyślnie jest to pusty ciąg dla mnie w FF.
Brett Zamir
6

Opierając się na tej wspaniałej odpowiedzi , możesz ją uprościć jeszcze bardziej, używając ES2015 +:

function isScrolledIntoView(el) {
  const { top, bottom } = el.getBoundingClientRect()
  return top >= 0 && bottom <= window.innerHeight
}

Jeśli nie obchodzi cię, że góra wychodzi z okna i zależy ci tylko na tym, że dno zostało obejrzane, można to uprościć

function isSeen(el) {
  return el.getBoundingClientRect().bottom <= window.innerHeight
}

a nawet jednowarstwowy

const isSeen = el => el.getBoundingClientRect().bottom <= window.innerHeight
rpearce
źródło
4

Możesz użyć wtyczki jquery „onScreen”, aby sprawdzić, czy element znajduje się w bieżącej rzutni podczas przewijania. Wtyczka ustawia „: onScreen” selektora na true, gdy selektor pojawi się na ekranie. To jest link do wtyczki, którą możesz dołączyć do swojego projektu. „ http://benpickles.github.io/onScreen/jquery.onscreen.min.js

Możesz wypróbować poniższy przykład, który działa dla mnie.

$(document).scroll(function() {
    if($("#div2").is(':onScreen')) {
        console.log("Element appeared on Screen");
        //do all your stuffs here when element is visible.
    }
    else {
        console.log("Element not on Screen");
        //do all your stuffs here when element is not visible.
    }
});

Kod HTML:

<div id="div1" style="width: 400px; height: 1000px; padding-top: 20px; position: relative; top: 45px"></div> <br>
<hr /> <br>
<div id="div2" style="width: 400px; height: 200px"></div>

CSS:

#div1 {
    background-color: red;
}
#div2 {
    background-color: green;
}
Vasuki Dileep
źródło
3

Mam taką metodę w mojej aplikacji, ale nie używa ona jQuery:

/* Get the TOP position of a given element. */
function getPositionTop(element){
    var offset = 0;
    while(element) {
        offset += element["offsetTop"];
        element = element.offsetParent;
    }
    return offset;
}

/* Is a given element is visible or not? */
function isElementVisible(eltId) {
    var elt = document.getElementById(eltId);
    if (!elt) {
        // Element not found.
        return false;
    }
    // Get the top and bottom position of the given element.
    var posTop = getPositionTop(elt);
    var posBottom = posTop + elt.offsetHeight;
    // Get the top and bottom position of the *visible* part of the window.
    var visibleTop = document.body.scrollTop;
    var visibleBottom = visibleTop + document.documentElement.offsetHeight;
    return ((posBottom >= visibleTop) && (posTop <= visibleBottom));
}

Edycja: Ta metoda działa dobrze dla IE (przynajmniej wersja 6). Przeczytaj komentarze dotyczące zgodności z FF.

Romain Linsolas
źródło
2
Z jakiegoś powodu document.body.scrollTop zawsze zwraca 0 (na ff3). Zmień go na var visibleTop = (document.documentElement.scrollTop? Document.documentElement.scrollTop: document.body.scrollTop);
yoavf
Przepraszam za to. Moja aplikacja musi działać tylko w IE 6 (tak, nie mam szczęścia :(), więc nigdy nie testowałem tego w FF ...
Romain Linsolas
To byłaby najlepsza odpowiedź tutaj, gdyby była poprawna. Popraw jedną z twoich linii do tego: var visibleBottom = visibleTop + window.innerHeight;nie używam jQuery i pomogłeś mi znaleźć poprawną odpowiedź.
Bitterblue
3

Jeśli chcesz dostosować to do przewijania elementu w innym dziale,

function isScrolledIntoView (elem, divID) 

{

    var docViewTop = $('#' + divID).scrollTop();


    var docViewBottom = docViewTop + $('#' + divID).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); 
}
Samiya Akhtar
źródło
3

Zmodyfikowano zaakceptowaną odpowiedź, tak że element musi mieć ustawioną właściwość display na wartość inną niż „none”, aby jakość była widoczna.

function isScrolledIntoView(elem) {
   var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();

  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();
  var elemDisplayNotNone = $(elem).css("display") !== "none";

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop) && elemDisplayNotNone);
}
evanmcd
źródło
3

Oto sposób na osiągnięcie tego samego za pomocą Mootools, w poziomie, pionie lub obu.

Element.implement({
inVerticalView: function (full) {
    if (typeOf(full) === "null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewTop = windowScroll.y;
    var docViewBottom = docViewTop + windowSize.y;
    var elemTop = elementPosition.y;
    var elemBottom = elemTop + elementSize.y;

    if (full) {
        return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
            && (elemBottom <= docViewBottom) && (elemTop >= docViewTop) );
    } else {
        return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
    }
},
inHorizontalView: function(full) {
    if (typeOf(full) === "null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewLeft = windowScroll.x;
    var docViewRight = docViewLeft + windowSize.x;
    var elemLeft = elementPosition.x;
    var elemRight = elemLeft + elementSize.x;

    if (full) {
        return ((elemRight >= docViewLeft) && (elemLeft <= docViewRight)
            && (elemRight <= docViewRight) && (elemLeft >= docViewLeft) );
    } else {
        return ((elemRight <= docViewRight) && (elemLeft >= docViewLeft));
    }
},
inView: function(full) {
    return this.inHorizontalView(full) && this.inVerticalView(full);
}});
bmlkc
źródło
3

Przykład oparty na tej odpowiedzi, aby sprawdzić, czy element jest widoczny w 75% (tj. Mniej niż 25% jest poza ekranem).

function isScrolledIntoView(el) {
  // check for 75% visible
  var percentVisible = 0.75;
  var elemTop = el.getBoundingClientRect().top;
  var elemBottom = el.getBoundingClientRect().bottom;
  var elemHeight = el.getBoundingClientRect().height;
  var overhang = elemHeight * (1 - percentVisible);

  var isVisible = (elemTop >= -overhang) && (elemBottom <= window.innerHeight + overhang);
  return isVisible;
}
Brendan Nee
źródło
3

Istnieje ponad 30 odpowiedzi na to pytanie i żadne z nich nie korzysta z niezwykle prostego, czystego rozwiązania JS, którego używałem. Nie ma potrzeby ładowania jQuery tylko po to, aby rozwiązać ten problem, ponieważ wiele innych pcha.

Aby stwierdzić, czy element znajduje się w rzutni, musimy najpierw ustalić pozycję elementów w ciele. Nie musimy tego robić rekurencyjnie, jak kiedyś myślałem. Zamiast tego możemy użyć element.getBoundingClientRect().

pos = elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top;

Ta wartość jest różnicą Y między górą obiektu a górą ciała.

Następnie musimy stwierdzić, czy element jest w widoku. Większość implementacji pyta, czy pełny element znajduje się w okienku ekranu, więc to omówimy.

Przede wszystkim położenie górnej części okna jest: window.scrollY.

Możemy uzyskać dolną pozycję okna, dodając wysokość okna do jego najwyższej pozycji:

var window_bottom_position = window.scrollY + window.innerHeight;

Stwórzmy prostą funkcję do uzyskania najwyższej pozycji elementu:

function getElementWindowTop(elem){
    return elem && typeof elem.getBoundingClientRect === 'function' ? elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top : 0;
}

Ta funkcja zwróci najwyższą pozycję elementu w oknie lub powróci, 0jeśli przekażesz mu coś innego niż element z.getBoundingClientRect() metody Ta metoda istnieje od dłuższego czasu, więc nie powinieneś się martwić, że Twoja przeglądarka jej nie obsługuje.

Teraz najwyższą pozycją naszego elementu jest:

var element_top_position = getElementWindowTop(element);

I lub dolna pozycja elementu to:

var element_bottom_position = element_top_position + element.clientHeight;

Teraz możemy ustalić, czy element znajduje się w rzutni, sprawdzając, czy dolne położenie elementu jest niższe niż górne położenie rzutni i sprawdzając, czy górne położenie elementu jest wyższe niż dolne położenie rzutni:

if(element_bottom_position >= window.scrollY 
&& element_top_position <= window_bottom_position){
    //element is in view
else
    //element is not in view

Stamtąd możesz wykonać logikę, aby dodać lub usunąć in-viewklasę w elemencie, którą możesz później obsłużyć za pomocą efektów przejścia w CSS.

Jestem absolutnie zaskoczony, że nie znalazłem tego rozwiązania nigdzie indziej, ale wierzę, że jest to najczystsze i najbardziej skuteczne rozwiązanie i nie wymaga załadowania jQuery!

WebWanderer
źródło
Bardzo miłe wytłumaczenie! Ale są już odpowiedzi, które robią dokładnie to, co robisz, jak odpowiedź Ally
Domysee,
1
@Domysee Hmm, jakoś to pominąłem. Słusznie. Dziękuję za zwrócenie na to uwagi. Miło jest widzieć to zrobione w inny sposób.
WebWanderer,
3

Bardziej wydajna wersja tej odpowiedzi :

 /**
 * Is element within visible region of a scrollable container
 * @param {HTMLElement} el - element to test
 * @returns {boolean} true if within visible region, otherwise false
 */
 function isScrolledIntoView(el) {
      var rect = el.getBoundingClientRect();
      return (rect.top >= 0) && (rect.bottom <= window.innerHeight);
 }
John Doherty
źródło
2

Ta metoda zwróci true, jeśli jakakolwiek część elementu jest widoczna na stronie. W moim przypadku działało to lepiej i może pomóc komuś innemu.

function isOnScreen(element) {
  var elementOffsetTop = element.offset().top;
  var elementHeight = element.height();

  var screenScrollTop = $(window).scrollTop();
  var screenHeight = $(window).height();

  var scrollIsAboveElement = elementOffsetTop + elementHeight - screenScrollTop >= 0;
  var elementIsVisibleOnScreen = screenScrollTop + screenHeight - elementOffsetTop >= 0;

  return scrollIsAboveElement && elementIsVisibleOnScreen;
}
Rafael Garcia
źródło
2

Prosta modyfikacja dla przewijalnego div (kontenera)

var isScrolledIntoView = function(elem, container) {
    var containerHeight = $(container).height();
    var elemTop = $(elem).position().top;
    var elemBottom = elemTop + $(elem).height();
    return (elemBottom > 0 && elemTop < containerHeight);
}

UWAGA: to nie działa, jeśli element jest większy niż przewijalny div.

Derrick J Wippler
źródło
2

Zaadaptowałem to krótkie rozszerzenie funkcji jQuery, z którego możesz swobodnie korzystać (licencja MIT).

/**
 * returns true if an element is visible, with decent performance
 * @param [scope] scope of the render-window instance; default: window
 * @returns {boolean}
 */
jQuery.fn.isOnScreen = function(scope){
    var element = this;
    if(!element){
        return;
    }
    var target = $(element);
    if(target.is(':visible') == false){
        return false;
    }
    scope = $(scope || window);
    var top = scope.scrollTop();
    var bot = top + scope.height();
    var elTop = target.offset().top;
    var elBot = elTop + target.height();

    return ((elBot <= bot) && (elTop >= top));
};
Lorenz Lo Sauer
źródło
2

Napisałem komponent do tego zadania, zaprojektowany do obsługi bardzo dużej liczby elementów bardzo szybko (do melodii <10ms dla 1000 elementów na powolnym telefonie komórkowym ).

To działa z każdym typem przewijania pojemniku masz dostęp do - okna, elementy HTML, osadzonym iframe, zrodził okna potomnego - i jest bardzo elastyczny, co wykryje ( pełne lub częściowe widoczność , pole granicy lub zawartość pola , niestandardowe pole tolerancji , etc ).

Ogromny, głównie automatycznie generowany pakiet testowy zapewnia, że ​​działa on jak reklama, w różnych przeglądarkach .

Spróbuj, jeśli chcesz: jQuery.isInView . W przeciwnym razie możesz znaleźć inspirację w kodzie źródłowym, np . Tutaj .

hashchange
źródło