Bagaimana cara memeriksa apakah elemen terlihat setelah menggulir?

1170

Saya memuat elemen melalui AJAX. Beberapa di antaranya hanya terlihat jika Anda menggulir ke bawah halaman.
Apakah ada cara saya bisa tahu jika suatu elemen sekarang di bagian yang terlihat dari halaman?

yoavf
sumber
42
maksudnya dia ingin metode mengetahui apakah elemen yang diberikan ditampilkan di jendela browser, atau jika pengguna perlu menggulir untuk melihatnya.
Romain Linsolas
1
Untuk memeriksa apakah suatu elemen terlihat sepenuhnya dalam sebuah wadah, cukup tambahkan param pemilih ekstra dan gunakan kembali kode elem untuknya. Library.IsElementVisibleInContainer = function (elementSelector, containerSelector) { var containerViewTop = $(containerSelector).offset().top; var containerViewBottom = containerViewTop + $(containerSelector).height();
Lifes
4
kemungkinan duplikat dari Bagaimana mengetahui apakah elemen DOM terlihat di viewport saat ini?
Audrius Meskauskas
1
Semua jawaban akan memicu reflow sehingga bisa jadi leher botol, Anda berteriak menggunakan IntersectionObserver jika didukung. Ini akan memiliki kinerja yang lebih baik di peramban modern,
jcubic

Jawaban:

1258

Ini harus melakukan trik:

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));
}

Fungsi Utilitas Sederhana Ini akan memungkinkan Anda untuk memanggil fungsi utilitas yang menerima elemen yang Anda cari dan jika Anda ingin elemen tersebut sepenuhnya terlihat atau sebagian.

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();

Pemakaian

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

if (isElementInView) {
    console.log('in view');
} else {
    console.log('out of view');
}
Scott Dowding
sumber
52
Perhatikan bahwa ini hanya berfungsi jika dokumen adalah elemen yang sedang digulir, yaitu Anda tidak memeriksa visibilitas beberapa elemen di dalam panel bagian dalam gulir.
Andrew B.
8
bagaimana cara menambahkan sedikit offset?
Jürgen Paul
5
Hanya bekerja ketika saya menggunakannya window.innerHeightsebagai gantinya
Christian Schnorr
2
Karena elemTopaku dulu $(elem).position().topdan elemBottomaku dulu elemTop + $(elem).outerHeight(true).
Kapal Sarah
13
Untuk: "Bagian mana pun dari elemen yang dilihat", saya menggunakan: (((elemTop> = docViewTop) && (elemTop <= docViewBottom)) || ((elemBottom> = docViewTop) && (elemBottom <= docViewBottom)))
Grizly
415

Jawaban ini di Vanilla:

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;
}
bravedick
sumber
27
bukankah ini seharusnya isVisible = elementTop < window.innerHeight && elementBottom >= 0? Jika tidak, setengah elemen pada layar mengembalikan false.
gman
7
tidak. saya memeriksa apakah beberapa elemen terlihat sepenuhnya di halaman. jika Anda ingin memeriksa visibilitas beberapa bagian - Anda dapat menyesuaikan cuplikan ini.
bravedick
15
Saya menemukan jawaban ini lebih baik daripada jawaban yang dipilih. Lebih sederhana juga.
Adam Venezia
12
Dibandingkan dengan jawaban yang disetujui, ini melakukan waaaay jauh lebih baik dengan ratusan elemen.
ncla
5
lihat biola kecil berdemonstrasi di sini - jsfiddle.net/shaaraddalvi/4rp09jL0
upInCloud
122

Pembaruan: gunakan IntersectionObserver


Metode terbaik yang saya temukan sejauh ini adalah plugin jQueryerge . Bekerja seperti pesona.

Meniru peristiwa "muncul" tersuai, yang menyala ketika suatu elemen bergulir ke tampilan atau terlihat oleh pengguna.

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

Plugin ini dapat digunakan untuk mencegah permintaan yang tidak perlu untuk konten yang tersembunyi atau di luar area yang dapat dilihat.

Joe Lencioni
sumber
30
Ini adalah plugin yang keren, tidak diragukan lagi, tetapi tidak menjawab pertanyaan.
Jon Adams
5
Sementara plugin jQuery-looks baik untuk konten di area halaman utama, sayangnya ada masalah dengan div ukuran bergulir dengan overflow. Peristiwa dapat menyala sebelum waktunya ketika elemen terikat berada di dalam area yang bisa dilihat halaman tetapi di luar area yang dapat dilihat div dan kemudian tidak menyala seperti yang diharapkan ketika elemen muncul di div.
Peter
17
Apakah ada plugin yang hilang?
Shamoon
3
@Shamoon memeriksa sumber untuk appear plugindan Anda mungkin hanya perlu menambahkan !tempat untuk mendapatkan disappearplugin.
Lucky Soni
5
Sebagai catatan, ini tidak berfungsi dengan jQuery 1.11.X github.com/morr/jquery.appear/issues/37
Jason Parham
86

Inilah solusi JavaScript murni saya yang berfungsi jika tersembunyi di dalam wadah yang dapat digulir juga.

Demo di sini (coba ubah ukuran jendela juga)

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
};

EDIT 2016-03-26: Saya telah memperbarui solusi untuk akun untuk menggulir melewati elemen sehingga tersembunyi di atas bagian atas wadah yang dapat digulir. EDIT 2018-10-08: Diperbarui untuk menangani ketika digulirkan dari tampilan di atas layar.

Sekutu
sumber
terima kasih, mungkin lebih baik return top <= document.documentElement.clientHeight && top >= 0;
Yousef Salimpour
16
+1 Ini adalah satu-satunya jawaban yang diberi kode (yaitu bukan pihak ketiga) yang mempertimbangkan sifat rekursif elemen. Saya telah memperluas untuk menangani gulir horizontal, vertikal, dan halaman: jsfiddle.net/9nuqpgqa
Pebbl
3
Solusi ini hanya memeriksa bagian atas elemen. Jika piksel teratas pertama terlihat, itu akan mengembalikan true bahkan jika sisa item tidak terlihat. Untuk memeriksa apakah seluruh elemen terlihat, Anda perlu memeriksa properti terbawah juga.
Wojciech Jakubas
2
Aye, rapi! Digunakan untuk membantu menulis jawaban ini (dengan kredit sebagai komentar js).
Roamer-1888
Tidak ada; setelah "return false" kedua dalam loop
Mikhail Ramendik
46

Menggunakan IntersectionObserver API (asli di browser modern)

Mudah & efisien untuk menentukan apakah suatu elemen terlihat di viewpor, atau dalam wadah yang dapat digulir, dengan menggunakan pengamat .

Kebutuhan untuk melampirkan scrollacara dan secara manual memeriksa event callback dihilangkan, sehingga efisiensi:

// 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>


Lihat tabel dukungan browser (tidak didukung di IE / Safari)

vsync
sumber
4
Terima kasih! Ini berfungsi untuk saya dan juga berfungsi di IE11
Matt Wilson
Sejauh ini solusi terbaik. Bekerja di IE11 tanpa polyfill!
Fabian von Ellerts
Perhatikan bahwa MASIH ini tidak didukung di iOS / macOS Safari, sayangnya. Pastikan untuk memeriksa masalah perf jika Anda memilih untuk melakukan polyfill, itu adalah sekelompok besar pengguna
Leland
@ Tanah - itu tergantung proyek. untuk semua proyek saya ini adalah grup pengguna 0 mutlak. Saya tidak membangun situs web tetapi sistem web;)
vsync
saya mencoba menjalankan ini dalam satu lingkaran pada beberapa elemen, tetapi tidak berfungsi. Ada ide? Saya menambahkan elemen ke target di loop itu.
Sascha Grindau
42

Plugin jQuery Waypoints berjalan sangat baik di sini.

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

Ada beberapa contoh di situs plugin .

Fedir RYKHTIK
sumber
3
Bagi saya itu hanya bekerja dengan offset $('#my-div').waypoint(function() { console.log('Hello there!'); }, { offset: '100%' });
leymannx
21

Bagaimana tentang

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

Setelah itu, Anda dapat memicu apa pun yang Anda inginkan setelah elemen dalam tampilan seperti ini

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

Itu baik-baik saja bagi saya

webicy
sumber
1
Ini berfungsi untuk saya, tetapi saya menggunakan, fungsi yang tampaknya lebih lengkap, isScrolledIntoView di stackoverflow.com/questions/487073/... :)
Meetai.com
3
Saya pikir itu harus $ (window) .scrollTop () <$ (elem) .offset (). Top + $ (elem) .height ();
Young
Modifikasi saya akan seperti ini: `return $ (window) .scrollTop () + $ (window) .height ()> $ (elem) .offset (). Top + $ (elem) .height (); `
bubencode
15

WebResourcesDepot menulis skrip untuk dimuat saat menggulir yang menggunakan jQuery beberapa waktu lalu. Anda dapat melihat Demo Langsung mereka Di Sini . Fungsi mereka adalah sebagai berikut:

$(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
sumber
15

Fungsi keren Tweeked Scott Dowding untuk kebutuhan saya - ini digunakan untuk menemukan apakah elemen tersebut baru saja menggulir ke layar yaitu tepi atas.

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

Vanila polos untuk memeriksa apakah elemen ( el) terlihat di div yang dapat digulir ( 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
},

Penggunaan dengan jQuery:

var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);
Denis Matafonov
sumber
2
Di era Aplikasi Halaman Tunggal ini menjadi lebih umum untuk memeriksa apakah suatu elemen terlihat dalam beberapa elemen lain selain jendela . Itu sebabnya yang satu ini mendapat saya upvote.
H Dog
8

isScrolledIntoView adalah fungsi yang sangat diperlukan, jadi saya mencobanya, berfungsi untuk elemen yang tidak lebih tinggi dari viewport, tetapi jika elemen lebih besar karena viewport tidak berfungsi. Untuk memperbaikinya dengan mudah ubah kondisinya

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

untuk ini:

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

Lihat demo di sini: http://jsfiddle.net/RRSmQ/

Robert
sumber
8

Sebagian besar jawaban di sini tidak memperhitungkan bahwa suatu elemen juga dapat disembunyikan karena itu digulirkan dari pandangan div, tidak hanya seluruh halaman.

Untuk menutupi kemungkinan itu, Anda pada dasarnya harus memeriksa apakah elemen diposisikan di dalam batas masing-masing orang tuanya.

Solusi ini melakukan hal itu:

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;
};

Ini juga memungkinkan Anda menentukan berapa persentase yang harus terlihat di setiap arah.
Itu tidak mencakup kemungkinan bahwa itu mungkin disembunyikan karena faktor lain, seperti display: hidden.

Ini harus bekerja di semua browser utama, karena hanya digunakan getBoundingClientRect. Saya pribadi mengujinya di Chrome dan Internet Explorer 11.

Domysee
sumber
Terima kasih untuk kode ini. Saya ingin tahu bagaimana Anda akan menambahkan pendengar acara pada gulir dalam hal ini Anda memiliki beberapa elemen digulir bersarang? Sepertinya menambahkan pendengar ke jendela saja tidak cukup, apakah kita harus menelusuri kembali ke induk atas untuk menambahkan pendengar ke setiap wadah yang dapat digulir?
mr1031011
@ mr1031011 Harus mungkin untuk menambahkan pawang ke jendela dan kemudian memeriksa target untuk mengidentifikasi wadah yang telah digulir.
Domysee
benar, itu tidak bekerja dengan contoh yang diberikan oleh @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
sumber
7

Berikut ini solusi lain dari 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>

Lihat di JSFiddle

Adrian P.
sumber
7

Ini mempertimbangkan padding, border, atau margin elemen yang dimiliki serta elemen yang lebih besar dari viewport itu sendiri.

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);
}

Untuk menyebutnya gunakan sesuatu seperti ini:

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

console.log(canUserSeeIt); // true, if element is visible; false otherwise
Brent Barbata
sumber
7

Ada plugin untuk jQuery yang disebut inview yang menambahkan acara "inview" baru.


Berikut ini beberapa kode untuk plugin jQuery yang tidak menggunakan acara:

$.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 );

Saya menemukan ini dalam komentar di sini ( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ ) oleh seorang pria bernama James

ness-EE
sumber
Sayangnya, jQuery inview tidak lagi dipertahankan dan tidak berfungsi dengan versi jQuery saat ini.
mikemaccana
1
JQuery 1 adalah untuk dukungan browser lawas, fitur-fitur baru ada di jQuery 2.
mikemaccana
Tautan tidak menunjukkan contoh karena halaman telah diperbarui.
Profesor pemrograman
6

Saya perlu memeriksa visibilitas pada elemen di dalam wadah DIV yang dapat digulir

    //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
sumber
ini berfungsi untuk saya jika saya mengubah e.style.opacity > 0ke (!e.style.opacity || e.style.opacity > 0)karena secara default itu adalah string kosong untuk saya di FF.
Brett Zamir
6

Membangun dari jawaban hebat ini , Anda dapat menyederhanakannya sedikit lebih jauh menggunakan ES2015 +:

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

Jika Anda tidak peduli tentang bagian atas keluar dari jendela dan hanya peduli bahwa bagian bawah telah dilihat, ini dapat disederhanakan

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

atau bahkan satu-liner

const isSeen = el => el.getBoundingClientRect().bottom <= window.innerHeight
Penghargaan
sumber
4

Anda dapat menggunakan plugin jquery "onScreen" untuk memeriksa apakah elemen tersebut ada di viewport saat ini ketika Anda menggulir. Plugin mengatur ": onScreen" pemilih menjadi true ketika pemilih muncul di layar. Ini adalah tautan untuk plugin yang dapat Anda sertakan dalam proyek Anda. " http://benpickles.github.io/onScreen/jquery.onscreen.min.js "

Anda dapat mencoba contoh di bawah ini yang berfungsi untuk saya.

$(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.
    }
});

Kode 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
sumber
3

Saya memiliki metode seperti itu dalam aplikasi saya, tetapi tidak menggunakan 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));
}

Sunting: Metode ini bekerja dengan baik untuk IE (setidaknya versi 6). Baca komentar untuk kompatibilitas dengan FF.

Romain Linsolas
sumber
2
Untuk beberapa alasan, document.body.scrollTop selalu mengembalikan 0 (pada ff3). Ubah ke var visibleTop = (document.documentElement.scrollTop? Document.documentElement.scrollTop: document.body.scrollTop);
yoavf
Maaf untuk itu. Aplikasi saya harus berjalan hanya di IE 6 (ya, saya tidak beruntung :(), jadi saya tidak pernah menguji ini di FF ...
Romain Linsolas
Ini akan menjadi jawaban terbaik di sini jika itu benar. Perbaiki salah satu baris Anda untuk ini: var visibleBottom = visibleTop + window.innerHeight;Saya tidak menggunakan jQuery dan Anda membantu saya menemukan jawaban yang benar.
Bitterblue
3

Jika Anda ingin mengubah ini untuk menggulir item dalam div lain,

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
sumber
3

Dimodifikasi jawaban yang diterima sehingga elemen harus memiliki properti tampilan diatur ke sesuatu selain "tidak ada" agar kualitas terlihat.

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
sumber
3

Berikut adalah cara untuk mencapai hal yang sama menggunakan Mootools, secara horizontal, vertikal atau keduanya.

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
sumber
3

Contoh didasarkan dari jawaban ini untuk memeriksa apakah suatu elemen terlihat 75% (yaitu kurang dari 25% tidak aktif di layar).

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
sumber
3

Ada lebih dari 30 jawaban untuk pertanyaan ini, dan tidak satupun dari mereka menggunakan solusi JS murni yang sangat sederhana yang telah saya gunakan. Tidak perlu memuat jQuery hanya untuk menyelesaikan ini, karena banyak yang mendorong.

Untuk mengetahui apakah elemen tersebut berada dalam viewport, pertama-tama kita harus menentukan posisi elemen dalam tubuh. Kita tidak perlu melakukan ini secara rekursif seperti yang pernah saya pikirkan. Sebagai gantinya, kita bisa menggunakan element.getBoundingClientRect().

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

Nilai ini adalah perbedaan Y antara bagian atas objek dan bagian atas tubuh.

Kami kemudian harus memberi tahu apakah elemen tersebut dalam tampilan. Sebagian besar implementasi bertanya apakah elemen lengkap berada dalam viewport, jadi inilah yang akan kita bahas.

Pertama-tama, posisi atas jendela adalah: window.scrollY.

Kita bisa mendapatkan posisi bawah jendela dengan menambahkan ketinggian jendela ke posisi atasnya:

var window_bottom_position = window.scrollY + window.innerHeight;

Mari kita membuat fungsi sederhana untuk mendapatkan posisi teratas elemen:

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

Fungsi ini akan mengembalikan posisi teratas elemen dalam jendela atau akan kembali 0jika Anda memberikan sesuatu selain elemen dengan .getBoundingClientRect()metode. Metode ini sudah ada sejak lama, jadi Anda tidak perlu khawatir browser Anda tidak mendukungnya.

Sekarang, posisi teratas elemen kami adalah:

var element_top_position = getElementWindowTop(element);

Dan posisi dasar elemen adalah:

var element_bottom_position = element_top_position + element.clientHeight;

Sekarang kita dapat menentukan apakah elemen tersebut dalam viewport dengan memeriksa apakah posisi bawah elemen lebih rendah dari posisi atas viewport dan dengan memeriksa apakah posisi teratas elemen lebih tinggi dari posisi bawah viewport:

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

Dari sana, Anda dapat melakukan logika untuk menambah atau menghapus in-viewkelas pada elemen Anda, yang kemudian dapat Anda tangani dengan efek transisi di CSS Anda.

Saya benar-benar kagum bahwa saya tidak menemukan solusi ini di tempat lain, tetapi saya percaya bahwa ini adalah solusi paling bersih dan paling efektif, dan itu tidak mengharuskan Anda memuat jQuery!

WebWanderer
sumber
Penjelasan yang sangat bagus! Tetapi sudah ada jawaban yang melakukan apa yang Anda lakukan, seperti jawaban Ally
Domysee
1
@ Domysee Hmm, saya entah bagaimana melompati itu. Cukup adil. Terima kasih telah menunjukkannya. Sangat menyenangkan melihat ini dilakukan dengan cara lain.
WebWanderer
3

Versi yang lebih efisien dari jawaban ini :

 /**
 * 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
sumber
2

Metode ini akan mengembalikan true jika ada bagian elemen yang terlihat di halaman. Ini bekerja lebih baik dalam kasus saya dan dapat membantu orang lain.

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
sumber
2

Modifikasi sederhana untuk div yang dapat digulir (wadah)

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

CATATAN: ini tidak berfungsi jika elemen lebih besar dari div yang dapat digulir.

Derrick J Wippler
sumber
2

Saya mengadaptasi ekstensi fungsi jQuery singkat ini, yang dapat Anda rasa bebas untuk digunakan (lisensi 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
sumber
2

Saya telah menulis sebuah komponen untuk tugas ini, yang dirancang untuk menangani sejumlah besar elemen dengan sangat cepat (hingga <10ms untuk 1000 elemen pada ponsel yang lambat ).

Ia bekerja dengan setiap jenis wadah gulir yang Anda miliki akses - jendela, elemen HTML, iframe tertanam, jendela anak spawned - dan sangat fleksibel dalam apa yang dideteksi ( visibilitas penuh atau sebagian , kotak batas atau kotak konten , zona toleransi khusus , dll. ).

Rangkaian uji yang sangat besar dan sebagian besar dihasilkan secara otomatis memastikan bahwa ia berfungsi seperti yang diiklankan, lintas-peramban .

Cobalah jika Anda suka: jQuery.isInView . Kalau tidak, Anda mungkin menemukan inspirasi dalam kode sumber, misalnya di sini .

hashchange
sumber