รับความสูงที่มองเห็นได้ของ div ด้วย jQuery


87

ฉันต้องการดึงความสูงที่มองเห็นได้ของ div ภายในพื้นที่ที่เลื่อนได้ ฉันคิดว่าตัวเองค่อนข้างดีกับ jQuery แต่นี่เป็นการทิ้งฉันไปโดยสิ้นเชิง

สมมติว่าฉันมี div สีแดงภายในกระดาษห่อสีดำ:

ในกราฟิกด้านบนฟังก์ชัน jQuery จะส่งคืน 248 ซึ่งเป็นส่วนที่มองเห็นได้ของ div

เมื่อผู้ใช้เลื่อนผ่านด้านบนสุดของ div ดังภาพด้านบนก็จะรายงาน 296

ตอนนี้เมื่อผู้ใช้เลื่อนผ่าน div ไปแล้วผู้ใช้จะรายงาน 248 อีกครั้ง

เห็นได้ชัดว่าตัวเลขของฉันจะไม่สม่ำเสมอและชัดเจนเหมือนที่อยู่ในการสาธิตนี้หรือฉันแค่ตั้งรหัสยากสำหรับตัวเลขเหล่านั้น

ฉันมีทฤษฎีเล็กน้อย:

  • รับความสูงของหน้าต่าง
  • รับความสูงของ div
  • รับค่าชดเชยเริ่มต้นของ div จากด้านบนของหน้าต่าง
  • รับค่าชดเชยเมื่อผู้ใช้เลื่อน
    • หากออฟเซ็ตเป็นค่าบวกแสดงว่าด้านบนของ div ยังมองเห็นได้
    • ถ้าเป็นค่าลบด้านบนของ div จะถูกปิดโดยหน้าต่าง ณ จุดนี้ div อาจใช้ความสูงทั้งหมดของหน้าต่างหรืออาจแสดงด้านล่างของ div ก็ได้
    • หากด้านล่างของ div ปรากฏขึ้นให้หาช่องว่างระหว่างมันกับด้านล่างของหน้าต่าง

ดูเหมือนจะค่อนข้างเรียบง่าย แต่ฉันไม่สามารถโอบรอบมันได้ พรุ่งนี้เช้าจะแตกอีก ฉันเพิ่งคิดว่าอัจฉริยะของคุณบางคนอาจช่วยได้

ขอบคุณ!

UPDATE: ฉันคิดออกด้วยตัวเอง แต่ดูเหมือนว่าหนึ่งในคำตอบด้านล่างนี้จะสวยกว่าดังนั้นฉันจะใช้คำตอบนั้นแทน สำหรับคนที่อยากรู้อยากเห็นนี่คือสิ่งที่ฉันคิดขึ้น:

$(document).ready(function() {
    var windowHeight = $(window).height();
    var overviewHeight = $("#overview").height();
    var overviewStaticTop = $("#overview").offset().top;
    var overviewScrollTop = overviewStaticTop - $(window).scrollTop();
    var overviewStaticBottom = overviewStaticTop + $("#overview").height();
    var overviewScrollBottom = windowHeight - (overviewStaticBottom - $(window).scrollTop());
    var visibleArea;
    if ((overviewHeight + overviewScrollTop) < windowHeight) {
        // alert("bottom is showing!");
        visibleArea = windowHeight - overviewScrollBottom;
        // alert(visibleArea);
    } else {
        if (overviewScrollTop < 0) {
            // alert("is full height");
            visibleArea = windowHeight;
            // alert(visibleArea);
        } else {
            // alert("top is showing");
            visibleArea = windowHeight - overviewScrollTop;
            // alert(visibleArea);
        }
    }
});

ฉันจะดูเป็นหน่วย vh 1vh = 1/100 ของความสูงของวิวพอร์ต คุณอาจจะพบวิธีแก้ปัญหานั้น ค้นหาความสูงของวิวพอร์ตความสูงขององค์ประกอบตำแหน่งองค์ประกอบและตำแหน่งการเลื่อนและคำนวณตามนั้น
davidcondrey

สมมติว่ามีขอบบน DIV ด้านในให้พูด "10px" รอบ ๆ ฉันจะตรวจจับความสูงของการเลื่อนเพื่อดูว่าผ่าน "10" หรือไม่จากนั้นฉันจะได้ความสูงขององค์ประกอบหลักลบออกตามความสูงของการเลื่อน

หากทุกอย่างล้มเหลวฉันเพิ่งเจอสคริปต์นี้ซึ่งดูเหมือนว่าอาจตอบสนองวัตถุประสงค์ที่คุณต้องการ: larsjung.de/fracs
davidcondrey

คำตอบ:


58

นี่คือแนวคิดที่รวดเร็วและสกปรก โดยทั่วไปจะเปรียบเทียบoffset().topองค์ประกอบกับด้านบนของหน้าต่างและoffset().top + height()ที่ด้านล่างของหน้าต่าง:

function getVisible() {    
    var $el = $('#foo'),
        scrollTop = $(this).scrollTop(),
        scrollBot = scrollTop + $(this).height(),
        elTop = $el.offset().top,
        elBottom = elTop + $el.outerHeight(),
        visibleTop = elTop < scrollTop ? scrollTop : elTop,
        visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    $('#notification').text(visibleBottom - visibleTop);
}

$(window).on('scroll resize', getVisible);

ตัวอย่างซอ

แก้ไข - อัปเดตขนาดเล็กเพื่อดำเนินการตามตรรกะเมื่อมีการปรับขนาดหน้าต่าง


ฉันมีปัญหาในการตั้งค่านี้สำหรับหลาย ๆ ตัวdivโดยไม่ต้องกรอกรหัสซ้ำ มีวิธีทำไหม?
JacobTheDev

2
@Rev นี่คุณไป: jsfiddle.net/b5DGj/1 ฉันแยกแต่ละองค์ประกอบออกเป็นการเรียกใช้ฟังก์ชันของตัวเอง คุณสามารถไปเพิ่มเติมและกำหนดปลั๊กอินเพื่อทำสิ่งนี้ให้คุณได้
Rory McCrossan

ฉันได้เขียนแนวทางของ @ RoryMcCrossan ใหม่เล็กน้อยในการทำหน้าที่เป็นปลั๊กอิน jQuery และโพสต์เป็นคำตอบด้านล่าง - อาจมีการใช้งานทั่วไปมากกว่าในรูปแบบนั้น
Michael.Lumley

บางครั้งองค์ประกอบอาจถูกซ่อนไว้บางส่วนเนื่องจากองค์ประกอบล้นหรือองค์ประกอบหลักโดยไม่คำนึงถึง "หน้าต่าง"
Nadav B

56

คำนวณจำนวนพิกเซลที่องค์ประกอบ (ความสูง) อยู่ในวิวพอร์ต

การสาธิตซอ

ฟังก์ชันเล็ก ๆ นี้จะส่งคืนจำนวนของpxองค์ประกอบที่มองเห็นได้ในวิวพอร์ต (แนวตั้ง) :

function inViewport($el) {
    var elH = $el.outerHeight(),
        H   = $(window).height(),
        r   = $el[0].getBoundingClientRect(), t=r.top, b=r.bottom;
    return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
}

ใช้เช่น:

$(window).on("scroll resize", function(){
  console.log( inViewport($('#elementID')) ); // n px in viewport
});

แค่นั้นแหละ.


jQuery .inViewport()ปลั๊กอิน

jsFiddle สาธิต

จากด้านบนคุณสามารถแยกตรรกะและสร้างปลั๊กอินเช่นนี้:

/**
 * inViewport jQuery plugin by Roko C.B.
 * http://stackoverflow.com/a/26831113/383904
 * Returns a callback function with an argument holding
 * the current amount of px an element is visible in viewport
 * (The min returned value is 0 (element outside of viewport)
 */
;(function($, win) {
  $.fn.inViewport = function(cb) {
     return this.each(function(i,el) {
       function visPx(){
         var elH = $(el).outerHeight(),
             H = $(win).height(),
             r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
         return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));  
       }
       visPx();
       $(win).on("resize scroll", visPx);
     });
  };
}(jQuery, window));

ใช้เช่น:

$("selector").inViewport(function(px) {
  console.log( px ); // `px` represents the amount of visible height
  if(px > 0) {
    // do this if element enters the viewport // px > 0
  }else{
    // do that if element exits  the viewport // px = 0
  }
}); // Here you can chain other jQuery methods to your selector

ตัวเลือกของคุณแบบไดนามิกจะฟังหน้าต่างscrollและresizeแต่ยังกลับค่าเริ่มต้นใน DOM pxรางพร้อมอาร์กิวเมนต์ฟังก์ชันการเรียกกลับครั้งแรก


ในการทำงานบน Android Chrome คุณอาจต้องเพิ่ม<meta name="viewport" content="width=your_size">ในส่วน html ส่วนหัว
userlond

@userlond ขอบคุณสำหรับการสนับสนุนของคุณ แต่ฉันไม่แน่ใจว่าcontent="width=1259"อาจเหมาะกับคนส่วนใหญ่ คุณลองcontent="width=device-width, initial-scale=1"แทนหรือยัง?
Roko C.Buljan

ไซต์มีเทมเพลตดั้งเดิมที่มีความกว้างคงที่และไม่ตอบสนอง ... ฉันคิดว่าคำแนะนำของคุณจะใช้ได้สำหรับคนส่วนใหญ่ เพื่อชี้แจง: หากโซลูชันของ Roko C.Buljan ไม่ได้ผลให้ลองเพิ่ม<meta name="viewport" content="your_content">การประกาศ :)
userlond

มันยอดเยี่ยมมากและใกล้เคียงกับสิ่งที่ฉันค้นหา ฉันจะคำนวณระยะทางจากองค์ประกอบด้านล่างถึงด้านล่างของหน้าต่างได้อย่างไร ฉันจึงสามารถโหลดเนื้อหาเพิ่มเติมก่อนที่คุณจะเห็นตอนท้ายของเนื้อหา ตัวอย่างเช่นถ้า elBottom <200 จาก windowBot ให้เริ่มการทำงานของ AJAX
ทม

1
เช่นกันวิธีการข้างต้นไม่ส่งคืนค่าเฉพาะอื่น ๆ (สามารถขยายเพื่อส่งคืนสิ่งต่างๆได้มากกว่าเพียงแค่visible height pxวัตถุดูซอนี้สำหรับแนวคิดดังกล่าว: jsfiddle.net/RokoCB/6xjq5gyy (คอนโซลนักพัฒนาแบบเปิด เพื่อดูบันทึก)
Roko C. Buljan

11

นี่คือแนวทางของ Rory เวอร์ชันข้างต้นยกเว้นที่เขียนขึ้นเพื่อทำหน้าที่เป็นปลั๊กอิน jQuery อาจมีการใช้งานทั่วไปมากกว่าในรูปแบบนั้น คำตอบที่ดี Rory - ขอบคุณ!

$.fn.visibleHeight = function() {
    var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop;
    scrollTop = $(window).scrollTop();
    scrollBot = scrollTop + $(window).height();
    elTop = this.offset().top;
    elBottom = elTop + this.outerHeight();
    visibleTop = elTop < scrollTop ? scrollTop : elTop;
    visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    return visibleBottom - visibleTop
}

สามารถเรียกได้ดังนี้:

$("#myDiv").visibleHeight();

jsFiddle


2
อย่าทำงานในกรณีที่หน้าต่างใหญ่ขึ้นและบล็อกได้พอดี นั่นคือเหตุผลที่เราต้องรีเซ็ตความสูงของบล็อก: $ (this) .css ('height', ''); jsfiddle.net/b5DGj/144
Max Koshel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.