วิธีการตรวจสอบว่าองค์ประกอบสามารถมองเห็นได้หลังจากเลื่อน?


1170

ฉันกำลังโหลดองค์ประกอบผ่าน AJAX บางส่วนจะปรากฏเฉพาะเมื่อคุณเลื่อนหน้าลง
มีวิธีใดที่ฉันจะรู้ได้ว่าตอนนี้องค์ประกอบอยู่ในส่วนที่มองเห็นได้ของหน้าเว็บหรือไม่?


42
เขาหมายถึงว่าเขาต้องการวิธีการที่จะรู้ว่าองค์ประกอบที่กำหนดจะปรากฏในหน้าต่างเบราว์เซอร์หรือถ้าผู้ใช้ต้องการเลื่อนดู
Romain Linsolas

1
ในการตรวจสอบว่าองค์ประกอบนั้นสามารถมองเห็นได้อย่างสมบูรณ์ในภาชนะบรรจุหรือไม่เพียงเพิ่มพารามิเตอร์ตัวเลือกพิเศษและใช้รหัส elem อีกครั้ง Library.IsElementVisibleInContainer = function (elementSelector, containerSelector) { var containerViewTop = $(containerSelector).offset().top; var containerViewBottom = containerViewTop + $(containerSelector).height();
Lifes



1
คำตอบทั้งหมดจะทริกเกอร์ reflow ดังนั้นมันอาจเป็นคอขวดคุณควรใช้IntersectionObserverถ้าคุณสนับสนุน มันจะมีประสิทธิภาพที่ดีขึ้นในเบราว์เซอร์รุ่นใหม่
jcubic

คำตอบ:


1258

สิ่งนี้ควรทำเคล็ดลับ:

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

ฟังก์ชั่นยูทิลิตี้ง่าย ๆ นี้จะช่วยให้คุณเรียกใช้ฟังก์ชั่นยูทิลิตี้ที่ยอมรับองค์ประกอบที่คุณกำลังมองหาและถ้าคุณต้องการให้องค์ประกอบในมุมมองหรือบางส่วน

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

การใช้

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

if (isElementInView) {
    console.log('in view');
} else {
    console.log('out of view');
}

52
โปรดทราบว่าจะใช้งานได้เฉพาะในกรณีที่เอกสารเป็นองค์ประกอบที่ถูกเลื่อนเช่นคุณไม่ได้ตรวจสอบการมองเห็นขององค์ประกอบบางอย่างภายในบานหน้าต่างด้านในเลื่อน
Andrew B.

8
วิธีเพิ่มออฟเซ็ตเล็กน้อย?
Jürgen Paul

5
ทำงานได้เฉพาะเมื่อฉันใช้window.innerHeightแทน
Christian Schnorr

2
สำหรับelemTopผมใช้$(elem).position().topและฉันใช้elemBottom elemTop + $(elem).outerHeight(true)
ซาร่าห์เรือ

13
คือ: "ส่วนหนึ่งขององค์ประกอบใด ๆ ในมุมมอง" ผมใช้: (((elemTop> = docViewTop) && (elemTop <= docViewBottom)) || ((elemBottom> = docViewTop) && (elemBottom <= docViewBottom)))
Grizly

415

คำตอบในวานิลลานี้:

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

27
ไม่ควรเป็นเช่นนี้isVisible = elementTop < window.innerHeight && elementBottom >= 0? มิฉะนั้นองค์ประกอบครึ่งหนึ่งบนหน้าจอจะคืนค่าเท็จ
gman

7
ไม่ ฉันตรวจสอบว่าองค์ประกอบบางอย่างสามารถมองเห็นได้อย่างสมบูรณ์บนหน้า หากคุณต้องการตรวจสอบการมองเห็นของชิ้นส่วน - คุณสามารถปรับแต่งตัวอย่างนี้
bravedick

15
ฉันค้นหาคำตอบนี้เพื่อให้ทำงานได้ดีกว่าคำตอบที่เลือก เรียบง่ายเหมือนกัน
Adam Venezia

12
เมื่อเปรียบเทียบกับคำตอบที่ได้รับการอนุมัติแล้วสิ่งนี้จะทำงานได้ดีขึ้นด้วยองค์ประกอบหลายร้อยรายการ
ncla

5
ดูซอเล็ก ๆ สาธิตที่นี่ - jsfiddle.net/shaaraddalvi/4rp09jL0
upInCloud

122

อัปเดต: ใช้IntersectionObserver


วิธีที่ดีที่สุดที่ฉันได้พบเพื่อให้ห่างไกลเป็นjQuery ปรากฏปลั๊กอิน ทำงานเหมือนจับใจ

เลียนแบบเหตุการณ์ "ปรากฏ" ที่กำหนดเองซึ่งจะเกิดขึ้นเมื่อองค์ประกอบเลื่อนเข้ามาดูหรือผู้ใช้จะมองเห็นได้

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

ปลั๊กอินนี้สามารถใช้เพื่อป้องกันคำขอที่ไม่จำเป็นสำหรับเนื้อหาที่ถูกซ่อนหรืออยู่นอกพื้นที่ที่สามารถดูได้


30
นี่เป็นปลั๊กอินที่เยี่ยมยอดไม่ต้องสงสัยเลย แต่ไม่ตอบคำถาม
Jon Adams

5
ในขณะที่ปลั๊กอิน jQuery-appear นั้นดีสำหรับเนื้อหาในพื้นที่หน้าหลัก แต่น่าเสียดายที่มีปัญหากับ divs การเลื่อนขนาดคงที่ที่มีมากเกินไป เหตุการณ์สามารถเริ่มทำงานก่อนกำหนดเมื่อองค์ประกอบที่ถูกผูกไว้อยู่ภายในพื้นที่ที่สามารถดูได้ของหน้า แต่อยู่นอกพื้นที่ที่สามารถดูได้ของ div และจะไม่ทำงานตามที่คาดไว้เมื่อองค์ประกอบเข้ามาดูใน div
ปีเตอร์

17
มีปลั๊กอินที่หายไปหรือไม่
Shamoon

3
@Shamoon ตรวจสอบแหล่งที่มาของappear pluginและคุณอาจจะต้องเพิ่มที่!อื่นเพื่อรับdisappearปลั๊กอิน
Lucky Soni

5
โปรดทราบว่าสิ่งนี้ไม่สามารถใช้ได้กับ jQuery 1.11.X github.com/morr/jquery.appear/issues/37
Jason Parham

86

นี่คือโซลูชัน JavaScript ของฉันบริสุทธิ์ที่ใช้งานได้หากซ่อนอยู่ภายในคอนเทนเนอร์ที่เลื่อนได้เช่นกัน

สาธิตที่นี่ (ลองปรับขนาดหน้าต่างด้วย)

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

แก้ไข 2016-03-26: ฉันได้อัปเดตโซลูชันเพื่อบัญชีสำหรับการเลื่อนองค์ประกอบที่ผ่านมาดังนั้นมันจึงซ่อนอยู่ด้านบนของคอนเทนเนอร์ที่เลื่อนได้ แก้ไข 2018-10-08: อัปเดตเพื่อจัดการเมื่อเลื่อนออกจากมุมมองด้านบนหน้าจอ


ขอบคุณบางทีอาจจะดีกว่า return top <= document.documentElement.clientHeight && top >= 0;
Yousef Salimpour

16
+1 นี่เป็นเพียงคำตอบที่เขียนโค้ดเท่านั้น (เช่นไม่ใช่บุคคลที่สาม) ที่คำนึงถึงลักษณะการเรียกซ้ำขององค์ประกอบ ฉันได้ขยายการจัดการเลื่อนแนวนอนแนวตั้งและหน้า: jsfiddle.net/9nuqpgqa
Pebbl

3
วิธีการแก้ปัญหานี้จะตรวจสอบด้านบนขององค์ประกอบเท่านั้น หากมองเห็นพิกเซลบนสุดตัวแรกมันจะกลับมาเป็นจริงแม้ว่าจะไม่สามารถมองเห็นส่วนที่เหลือของรายการได้ ในการตรวจสอบว่าองค์ประกอบทั้งหมดมองเห็นได้หรือไม่คุณต้องตรวจสอบคุณสมบัติด้านล่างด้วย
Wojciech Jakubas

2
ใช่เรียบร้อย! ใช้เพื่อช่วยเขียนคำตอบนี้ (มีเครดิตเป็นความคิดเห็น js)
Roamer-1888

หายไป; หลังจาก "return false" ที่สองในลูป
Mikhail Ramendik

45

ใช้IntersectionObserver API (ดั้งเดิมในเบราว์เซอร์สมัยใหม่)

มันเป็นเรื่องง่ายและมีประสิทธิภาพในการตรวจสอบว่าเป็นองค์ประกอบที่ปรากฏอยู่ใน viewpor หรือในภาชนะเลื่อนใด ๆ โดยใช้การสังเกตการณ์

ความจำเป็นในการแนบscrollเหตุการณ์และการตรวจสอบด้วยตนเองในการเรียกกลับเหตุการณ์จะถูกกำจัดดังนั้นประสิทธิภาพ:

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


ดูตารางการสนับสนุนเบราว์เซอร์ (ไม่รองรับใน IE / Safari)


4
ขอบคุณ! มันใช้งานได้สำหรับฉันและทำให้มันทำงานใน IE11 ด้วยgithub.com/w3c/IntersectionObserver
Matt Wilson

โดยไกลทางออกที่ดีที่สุด ทำงานใน IE11 โดยไม่ต้องใช้ polyfill!
Fabian von Ellerts

โปรดทราบว่ายังไม่รองรับ STILL ใน iOS / macOS Safari อย่าลืมตรวจสอบปัญหาที่สมบูรณ์แบบหากคุณเลือกที่จะ polyfill นั่นคือกลุ่มผู้ใช้ขนาดใหญ่
Leland

@Leland - มันขึ้นอยู่กับโครงการ สำหรับโครงการของฉันทั้งหมดนี่คือกลุ่มผู้ใช้ 0 คนแน่นอน ฉันไม่ได้สร้างเว็บไซต์ แต่เป็นระบบเว็บ;)
vsync

ฉันพยายามรันสิ่งนี้ในลักษณะวนซ้ำหลายองค์ประกอบ แต่มันไม่ทำงาน ความคิดใด ๆ ฉันกำลังเพิ่มองค์ประกอบที่จะกำหนดเป้าหมายในลูปนั้น
Sascha Grindau

42

ปลั๊กอิน jQuery Waypoints ทำได้ดีมากที่นี่

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

มีตัวอย่างบางอย่างเกี่ยวกับที่มีเว็บไซต์ของปลั๊กอิน


3
สำหรับฉันมันใช้ได้กับออฟเซ็ตเท่านั้น $('#my-div').waypoint(function() { console.log('Hello there!'); }, { offset: '100%' });
leymannx

21

เกี่ยวกับ

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

หลังจากนั้นคุณสามารถเรียกใช้สิ่งที่คุณต้องการเมื่อองค์ประกอบอยู่ในมุมมองเช่นนี้

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

สำหรับฉันแล้วก็ใช้ได้


1
สิ่งนี้ใช้งานได้สำหรับฉัน แต่ฉันใช้ฟังก์ชั่น isScrolledIntoView ที่สมบูรณ์กว่านี้ดูได้ที่stackoverflow.com/questions/487073/… :)
Meetai.com

3
ฉันคิดว่ามันควรจะเป็น $ (หน้าต่าง) .scrollTop () <$ (elem) .offset (). top + $ (elem) .height ();
หนุ่ม

การแก้ไขของฉันจะเป็นเช่นนี้: `return $ (หน้าต่าง) .scrollTop () + $ (หน้าต่าง) .height ()> $ (elem) .offset (). top + $ (elem) .height (); `
bubencode

15

WebResourcesDepotเขียนสคริปต์เพื่อโหลดขณะเลื่อนที่ใช้jQuery เมื่อสักครู่ที่ผ่านมา คุณสามารถดูพวกเขาสาธิตอาศัยอยู่ที่นี่ เนื้อวัวของการทำงานของพวกเขาคือ:

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

15

ฟังก์ชั่นเจ๋ง ๆ ของ Scott Dowding สำหรับความต้องการของฉัน - ใช้เพื่อค้นหาว่าองค์ประกอบเพิ่งเลื่อนเข้าสู่หน้าจอหรือไม่นั่นคือขอบด้านบน

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

12

วานิลลาธรรมดาเพื่อตรวจสอบว่าองค์ประกอบ ( el) สามารถมองเห็นได้ใน 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
},

การใช้งานกับ jQuery:

var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);

2
ในยุคของการประยุกต์ใช้งานเดี่ยวหน้านี้มันได้กลายเป็นเรื่องปกติมากขึ้นเพื่อตรวจสอบว่าเป็นองค์ประกอบที่จะมองเห็นได้ภายในองค์ประกอบอื่น ๆ นอกเหนือจากหน้าต่าง นั่นเป็นเหตุผลที่คนนี้ได้รับการโหวตของฉัน
H Dog

8

isScrolledIntoViewเป็นฟังก์ชั่นที่ต้องการอย่างมากดังนั้นฉันจึงลองมันใช้งานได้กับองค์ประกอบที่ไม่สูงกว่าวิวพอร์ต แต่ถ้าองค์ประกอบนั้นใหญ่กว่าวิวพอร์ตมันไม่ทำงาน เพื่อแก้ไขปัญหานี้ได้อย่างง่ายดายเปลี่ยนเงื่อนไข

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

สำหรับสิ่งนี้:

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

ดูตัวอย่างได้ที่นี่: http://jsfiddle.net/RRSmQ/


8

คำตอบส่วนใหญ่ที่นี่ไม่ได้คำนึงถึงองค์ประกอบที่สามารถซ่อนเนื่องจากเลื่อนออกจากมุมมองของ div ไม่เพียง แต่ของหน้าทั้งหมด

เพื่อให้ครอบคลุมความเป็นไปได้นั้นคุณจะต้องตรวจสอบองค์ประกอบที่อยู่ภายในขอบเขตของผู้ปกครองแต่ละคน

วิธีการแก้ปัญหานี้ไม่ว่า:

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

นอกจากนี้ยังช่วยให้คุณระบุเปอร์เซ็นต์ที่จะมองเห็นได้ในแต่ละทิศทาง
มันไม่ครอบคลุมความเป็นไปได้ว่ามันอาจจะถูกซ่อนไว้เนื่องจากปัจจัยอื่น ๆ display: hiddenเช่น

getBoundingClientRectนี้จะทำงานในเบราว์เซอร์ที่สำคัญทั้งหมดเพราะมันใช้เพียง ฉันทดสอบด้วยตนเองใน Chrome และ Internet Explorer 11


ขอบคุณสำหรับรหัสนี้ ฉันสงสัยว่าคุณจะเพิ่มผู้ฟังเหตุการณ์ในการเลื่อนในกรณีนี้ว่าคุณมีองค์ประกอบที่เลื่อนซ้อนกันหลายองค์ประกอบได้อย่างไร ดูเหมือนว่าการเพิ่ม listener ไปที่หน้าต่างเพียงอย่างเดียวไม่เพียงพอเราต้องย้อนกลับไปที่ parent บนสุดเพื่อเพิ่ม listener ให้กับ container ที่เลื่อนได้แต่ละอัน?
mr1031011

@ mr1031011 มันควรจะเป็นไปได้ที่จะเพิ่มตัวจัดการไปที่หน้าต่างแล้วตรวจสอบเป้าหมายเพื่อระบุภาชนะที่ถูกเลื่อน
Domysee

ถูกต้องมันไม่ทำงานกับตัวอย่างที่ได้รับจาก @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));
}

7

นี่คือทางออกอื่นจาก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>

ดูในJSFiddle


7

สิ่งนี้จะพิจารณาการแพ็ดขอบหรือระยะขอบขององค์ประกอบนั้นรวมถึงองค์ประกอบที่มีขนาดใหญ่กว่าวิวพอร์ตของตัวเอง

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

หากต้องการเรียกใช้สิ่งนี้:

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

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

7

มีปลั๊กอินสำหรับ jQuery ชื่อinviewซึ่งเพิ่มเหตุการณ์ "inview" ใหม่


นี่คือโค้ดสำหรับปลั๊กอิน jQuery ที่ไม่ได้ใช้เหตุการณ์:

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

ฉันพบสิ่งนี้ในความคิดเห็นที่นี่ ( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ ) โดยเจ้าหมอชื่อ James


อนิจจา jQuery inview ไม่ได้รับการดูแลรักษาอีกต่อไปและไม่สามารถใช้งานกับ jQuery เวอร์ชันปัจจุบันได้
mikemaccana

1
JQuery 1 ใช้สำหรับรองรับเบราว์เซอร์รุ่นเก่าคุณสมบัติใหม่อยู่ใน jQuery 2
mikemaccana

ลิงก์ไม่แสดงตัวอย่างเมื่อหน้าได้รับการอัปเดต
ศาสตราจารย์ด้านการเขียนโปรแกรม

6

ฉันต้องการตรวจสอบการมองเห็นองค์ประกอบภายในคอนเทนเนอร์ 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);
    }

งานนี้สำหรับฉันถ้าฉันเปลี่ยนe.style.opacity > 0ไป(!e.style.opacity || e.style.opacity > 0)เพราะโดยปกติจะเป็นสตริงที่ว่างเปล่าสำหรับผมใน FF
Brett Zamir

6

นอกเหนือจากคำตอบที่ยอดเยี่ยมนี้คุณสามารถทำให้ง่ายขึ้นอีกเล็กน้อยโดยใช้ ES2015 +:

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

หากคุณไม่สนใจเกี่ยวกับการออกไปนอกหน้าต่างด้านบนและเพียงแค่สนใจว่ามองจากด้านล่างสิ่งนี้สามารถทำให้ง่ายขึ้น

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

หรือแม้แต่ซับเดียว

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

4

คุณสามารถใช้ปลั๊กอิน jquery "บนหน้าจอ" เพื่อตรวจสอบว่าองค์ประกอบอยู่ในวิวพอร์ตปัจจุบันเมื่อคุณเลื่อน ปลั๊กอินตั้งค่า ": บนหน้าจอ" ของตัวเลือกเป็นจริงเมื่อตัวเลือกปรากฏบนหน้าจอ นี่คือลิงค์สำหรับปลั๊กอินที่คุณสามารถรวมไว้ในโครงการของคุณ " http://benpickles.github.io/onScreen/jquery.onscreen.min.js "

คุณสามารถลองตัวอย่างด้านล่างซึ่งเหมาะกับฉัน

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

รหัส 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;
}

3

ฉันมีวิธีการดังกล่าวในแอปพลิเคชันของฉัน แต่ไม่ได้ใช้ 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));
}

แก้ไข: วิธีนี้ใช้ได้ดีสำหรับ IE (อย่างน้อยรุ่น 6) อ่านความคิดเห็นสำหรับความเข้ากันได้กับ FF


2
ด้วยเหตุผลบางอย่าง document.body.scrollTop กลับ 0 (บน ff3) เสมอ เปลี่ยนเป็น var visibleTop = (document.documentElement.scrollTop? document.documentElement.scrollTop: document.body.scrollTop);
yoavf

ขอโทษสำหรับสิ่งนั้น. แอปพลิเคชันของฉันต้องทำงานเฉพาะใน IE 6 (ใช่ฉันไม่โชคดี :() ดังนั้นฉันจึงไม่เคยทดสอบสิ่งนี้ใน FF ...
Romain Linsolas

นี่จะเป็นคำตอบที่ดีที่สุดที่นี่ถ้ามันถูกต้อง แก้ไขหนึ่งในบรรทัดของคุณในสิ่งนี้: var visibleBottom = visibleTop + window.innerHeight;ฉันไม่ได้ใช้ jQuery และคุณช่วยฉันหาคำตอบที่ถูกต้อง
Bitterblue

3

หากคุณต้องการปรับแต่งนี้เพื่อเลื่อนรายการภายใน div อื่น

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

3

แก้ไขคำตอบที่ยอมรับเพื่อให้องค์ประกอบต้องมีคุณสมบัติการแสดงผลตั้งค่าเป็นอย่างอื่นที่ไม่ใช่ "ไม่มี" เป็นคุณภาพเท่าที่มองเห็น

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

3

นี่คือวิธีในการบรรลุสิ่งเดียวกันโดยใช้ Mootools ในแนวนอนแนวตั้งหรือทั้งสองอย่าง

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

3

ตัวอย่างที่ใช้คำตอบนี้เพื่อตรวจสอบว่าองค์ประกอบนั้นมองเห็นได้ 75% หรือไม่ (เช่นน้อยกว่า 25% ขององค์ประกอบนั้นอยู่นอกหน้าจอ)

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

3

มีคำตอบมากกว่า 30 ข้อสำหรับคำถามนี้และไม่มีใครใช้วิธีแก้ปัญหา JS ที่เรียบง่ายและน่าอัศจรรย์ที่ฉันใช้อยู่ ไม่จำเป็นต้องโหลด jQuery เพียงเพื่อแก้ปัญหานี้เนื่องจากมีหลาย ๆ ตัวที่กำลังผลักดัน

เพื่อที่จะบอกว่าองค์ประกอบอยู่ในวิวพอร์ตเราต้องกำหนดตำแหน่งองค์ประกอบภายในร่างกาย เราไม่จำเป็นต้องทำแบบนี้ซ้ำ ๆ ตามที่ฉันเคยคิด element.getBoundingClientRect()แต่เราสามารถใช้

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

ค่านี้คือความแตกต่าง Y ระหว่างส่วนบนของวัตถุและส่วนบนของร่างกาย

เราต้องบอกว่าองค์ประกอบนั้นอยู่ในมุมมองหรือไม่ การใช้งานส่วนใหญ่ถามว่าองค์ประกอบทั้งหมดอยู่ในวิวพอร์ตหรือไม่ดังนั้นนี่คือสิ่งที่เราจะครอบคลุม

ก่อนอื่นตำแหน่งบนสุดของหน้าต่างคือ: window.scrollY.

เราสามารถรับตำแหน่งด้านล่างของหน้าต่างโดยการเพิ่มความสูงของหน้าต่างไปที่ตำแหน่งบนสุด:

var window_bottom_position = window.scrollY + window.innerHeight;

ให้สร้างฟังก์ชั่นที่เรียบง่ายเพื่อรับตำแหน่งสูงสุดขององค์ประกอบ:

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

ฟังก์ชั่นนี้จะคืนค่าตำแหน่งบนสุดขององค์ประกอบภายในหน้าต่างหรือจะส่งคืน0ถ้าคุณผ่านสิ่งอื่นนอกเหนือจากองค์ประกอบที่มี.getBoundingClientRect()เมธอด วิธีนี้มีมานานแล้วดังนั้นคุณไม่ควรกังวลว่าเบราว์เซอร์ของคุณจะไม่รองรับ

ตอนนี้ตำแหน่งสูงสุดขององค์ประกอบของเราคือ:

var element_top_position = getElementWindowTop(element);

และตำแหน่งด้านล่างขององค์ประกอบคือ:

var element_bottom_position = element_top_position + element.clientHeight;

ตอนนี้เราสามารถตรวจสอบว่าองค์ประกอบอยู่ในวิวพอร์ตหรือไม่โดยตรวจสอบว่าตำแหน่งด้านล่างขององค์ประกอบนั้นต่ำกว่าตำแหน่งสูงสุดของวิวพอร์ตหรือไม่และตรวจสอบว่าตำแหน่งบนสุดขององค์ประกอบนั้นสูงกว่าตำแหน่งด้านล่างของวิวพอร์ตหรือไม่:

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

จากตรงนั้นคุณสามารถใช้ตรรกะเพื่อเพิ่มหรือลบin-viewคลาสในองค์ประกอบของคุณซึ่งคุณสามารถจัดการกับเอฟเฟกต์การเปลี่ยนแปลงใน CSS ของคุณในภายหลัง

ฉันประหลาดใจอย่างยิ่งที่ฉันไม่พบโซลูชันนี้ที่อื่น แต่ฉันเชื่อว่านี่เป็นโซลูชันที่สะอาดและมีประสิทธิภาพมากที่สุดและไม่ต้องการให้คุณโหลด jQuery!


คำอธิบายที่ดีมาก! แต่มีคำตอบอยู่แล้วว่าทำสิ่งที่คุณทำเช่นเดียวกับคำตอบของ Ally
Domysee

1
@Domysee อืมฉันก็ข้ามมันไป ยุติธรรมพอสมควร ขอบคุณสำหรับการชี้ให้เห็นว่า ดีใจที่ได้เห็นสิ่งนี้ทำได้อีกทางหนึ่ง
WebWanderer

3

รุ่นที่มีประสิทธิภาพมากขึ้นของคำตอบนี้ :

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

2

วิธีนี้จะคืนค่าจริงหากส่วนใดส่วนหนึ่งขององค์ประกอบปรากฏบนหน้า มันทำงานได้ดีขึ้นในกรณีของฉันและอาจช่วยคนอื่น

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

2

การดัดแปลงอย่างง่ายสำหรับ div ที่เลื่อนได้ (คอนเทนเนอร์)

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

หมายเหตุ: สิ่งนี้จะไม่ทำงานหากองค์ประกอบมีขนาดใหญ่กว่า div ที่เลื่อนได้


2

ฉันดัดแปลงส่วนขยายฟังก์ชั่นสั้น jQuery ซึ่งคุณสามารถใช้งานได้ (ใบอนุญาต 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));
};

2

ฉันได้เขียนส่วนประกอบสำหรับงานออกแบบมาเพื่อจัดการองค์ประกอบจำนวนมากอย่างรวดเร็วมาก (เพื่อปรับ <10ms สำหรับ 1,000 องค์ประกอบบนมือถือช้า )

จะทำงานร่วมกับประเภทของภาชนะเลื่อนทุกครั้งที่คุณมีการเข้าถึง - หน้าต่างองค์ประกอบ HTML, iframe ฝังหน้าต่างลูกกลับกลาย - และมีความยืดหยุ่นมากในสิ่งที่ตรวจพบ ( มองเห็นทั้งหมดหรือบางส่วน , กล่องชายแดนหรือกล่องเนื้อหาที่กำหนดเองโซนอดทน , ฯลฯ )

ขนาดใหญ่ส่วนใหญ่สร้างขึ้นโดยอัตโนมัติเพื่อให้แน่ใจชุดทดสอบว่ามันทำงานโฆษณาเป็นเบราว์เซอร์

ให้มันยิงถ้าคุณต้องการ: jQuery.isInView มิฉะนั้นคุณอาจพบแรงบันดาลใจในรหัสที่มาเช่นที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.