Cách kiểm tra xem một phần tử có nằm ngoài màn hình hay không


81

Tôi cần kiểm tra bằng jQuery nếu phần tử DIV không bị tắt màn hình. Các phần tử có thể nhìn thấy và hiển thị theo các thuộc tính CSS, nhưng chúng có thể bị cố ý đặt ra ngoài màn hình bằng cách:

position: absolute; 
left: -1000px; 
top: -1000px;

Tôi không thể sử dụng :visiblebộ chọn jQuery vì phần tử có chiều cao và chiều rộng khác 0.

Tôi không làm bất cứ điều gì hoa mỹ. Vị trí vị trí tuyệt đối này là cách khung công tác Ajax của tôi thực hiện ẩn / hiện của một số tiện ích con.


Tôi cũng đã đưa ra câu trả lời cho câu hỏi này cho câu hỏi 'trùng lặp' này: stackoverflow.com/questions/5353934/…
Tokimon

Câu trả lời:


135

Phụ thuộc vào định nghĩa của bạn về "ngoài màn hình". Đó là trong khung nhìn hay trong các ranh giới xác định trên trang của bạn?

Sử dụng Element.getBoundsClientRect (), bạn có thể dễ dàng phát hiện xem phần tử của mình có nằm trong giới hạn của khung nhìn hay không (tức là trên màn hình hoặc ngoài màn hình):

jQuery.expr.filters.offscreen = function(el) {
  var rect = el.getBoundingClientRect();
  return (
           (rect.x + rect.width) < 0 
             || (rect.y + rect.height) < 0
             || (rect.x > window.innerWidth || rect.y > window.innerHeight)
         );
};

Sau đó, bạn có thể sử dụng nó theo một số cách:

// returns all elements that are offscreen
$(':offscreen');

// boolean returned if element is offscreen
$('div').is(':offscreen');

2
Tôi thích điều này, nhưng nó bị hỏng nếu phần tử của bạn nằm bên trong vùng chứa có thể cuộn - phần tử ở cuối DIV cao 2 màn hình sẽ luôn ở "ngoài màn hình" vì chiều cao cửa sổ nhỏ hơn offsetTop của phần tử.
Coderer

@scurker Tôi không thể làm cho điều này hoạt động. Dưới đây là câu hỏi SO của tôi (với jsFiddle) về vấn đề này: stackoverflow.com/questions/26004098/...
crashwap

Tôi có sai ở đây khi nghĩ rằng điều này sẽ không xảy ra nếu el đã định vị cha mẹ (tuyệt đối hoặc tương đối) trước phần thân?
fekiri malek

@fekirimalek Bạn đang đúng, tôi đã cập nhật ví dụ vào tài khoản cho điều đó
scurker

7
Lưu ý rằng hiện tại (tháng 1 năm 2017) điều này sẽ không hoạt động ít nhất trên Chrome, vì Element.getBoundsClientRect () có các thuộc tính trên cùng, bên phải, dưới cùng và bên trái thay vì x và y.
Asu

18

Có một plugin jQuery ở đây cho phép người dùng kiểm tra xem một phần tử có nằm trong khung nhìn hiển thị của trình duyệt hay không, tính đến vị trí cuộn của trình duyệt.

$('#element').visible();

Bạn cũng có thể kiểm tra khả năng hiển thị một phần:

$('#element').visible( true);

Một nhược điểm là nó chỉ hoạt động với định vị / cuộn dọc, mặc dù có thể dễ dàng thêm định vị ngang vào hỗn hợp.


Đây là một plugin RẤT nhẹ. Tôi đã có thể có được một thanh điều hướng cố định khi cuộn lên và hoạt động phản hồi trong vòng vài phút sau khi thêm nó. Gợi ý tuyệt vời.
Nappstir 14/02/17

Plugin này rất nhẹ và khá dễ thực hiện. Đã giải quyết vấn đề tôi gặp phải với các menu phụ.
Theo Orphanos

9

Không cần plugin để kiểm tra xem có bên ngoài cổng xem hay không.

var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
var d = $(document).scrollTop();

$.each($("div"),function(){
    p = $(this).position();
    //vertical
    if (p.top > h + d || p.top > h - d){
        console.log($(this))
    }
    //horizontal
    if (p.left < 0 - $(this).width() || p.left > w){
        console.log($(this))
    }
});

1
Điều này sẽ hoạt động nếu bạn sử dụng $(this).offsetthay vì $this.position. Ngay bây giờ nó chỉ đang tính toán khoảng cách từ cha mẹ của nó, đó có thể là một div bao bọc nó một cách hoàn hảo.
Ryan Shillington

7

Chà ... Tôi đã tìm thấy một số vấn đề trong mọi giải pháp được đề xuất ở đây.

  • Bạn có thể chọn nếu bạn muốn toàn bộ phần tử hiển thị trên màn hình hay chỉ bất kỳ phần nào của nó
  • Các giải pháp được đề xuất không thành công nếu phần tử cao hơn / rộng hơn cửa sổ và kinda che cửa sổ trình duyệt.

Đây là giải pháp của tôi bao gồm jQuery .fnhàm phiên bản và expression. Tôi đã tạo nhiều biến bên trong hàm hơn mức có thể, nhưng đối với vấn đề logic phức tạp, tôi muốn chia nó thành các phần nhỏ hơn, được đặt tên rõ ràng.

Tôi đang sử dụng getBoundingClientRectphương thức trả về vị trí phần tử tương đối cho chế độ xem nên tôi không cần quan tâm đến vị trí cuộn

Sử dụng :

$(".some-element").filter(":onscreen").doSomething();
$(".some-element").filter(":entireonscreen").doSomething();
$(".some-element").isOnScreen(); // true / false
$(".some-element").isOnScreen(true); // true / false (partially on screen)
$(".some-element").is(":onscreen"); // true / false (partially on screen)
$(".some-element").is(":entireonscreen"); // true / false 

Nguồn :

$.fn.isOnScreen = function(partial){

    //let's be sure we're checking only one element (in case function is called on set)
    var t = $(this).first();

    //we're using getBoundingClientRect to get position of element relative to viewport
    //so we dont need to care about scroll position
    var box = t[0].getBoundingClientRect();

    //let's save window size
    var win = {
        h : $(window).height(),
        w : $(window).width()
    };

    //now we check against edges of element

    //firstly we check one axis
    //for example we check if left edge of element is between left and right edge of scree (still might be above/below)
    var topEdgeInRange = box.top >= 0 && box.top <= win.h;
    var bottomEdgeInRange = box.bottom >= 0 && box.bottom <= win.h;

    var leftEdgeInRange = box.left >= 0 && box.left <= win.w;
    var rightEdgeInRange = box.right >= 0 && box.right <= win.w;


    //here we check if element is bigger then window and 'covers' the screen in given axis
    var coverScreenHorizontally = box.left <= 0 && box.right >= win.w;
    var coverScreenVertically = box.top <= 0 && box.bottom >= win.h;

    //now we check 2nd axis
    var topEdgeInScreen = topEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );
    var bottomEdgeInScreen = bottomEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );

    var leftEdgeInScreen = leftEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );
    var rightEdgeInScreen = rightEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );

    //now knowing presence of each edge on screen, we check if element is partially or entirely present on screen
    var isPartiallyOnScreen = topEdgeInScreen || bottomEdgeInScreen || leftEdgeInScreen || rightEdgeInScreen;
    var isEntirelyOnScreen = topEdgeInScreen && bottomEdgeInScreen && leftEdgeInScreen && rightEdgeInScreen;

    return partial ? isPartiallyOnScreen : isEntirelyOnScreen;

};

$.expr.filters.onscreen = function(elem) {
  return $(elem).isOnScreen(true);
};

$.expr.filters.entireonscreen = function(elem) {
  return $(elem).isOnScreen(true);
};

1
Tôi nhận được make_footer_down.js: 8 Uncaught TypeError: Không thể đọc thuộc tính 'getBoundsClientRect' của undefined khi cố gắng sử dụng các hàm ur ở đó.
Ludvig W

Xin chào Lurr ... Tôi đã thử với $ ("# divId"). IsOnScreen (true); nơi 'divId' ở ngoài màn hình và nó trả về cho tôi 'false'; như vậy, tôi cảm thấy làm việc của nó
Anirban


1
  • Lấy khoảng cách từ đỉnh của phần tử đã cho
  • Thêm chiều cao của cùng một phần tử đã cho. Điều này sẽ cho bạn biết tổng số từ đầu màn hình đến cuối phần tử đã cho.
  • Sau đó, tất cả những gì bạn phải làm là trừ tổng chiều cao của tài liệu

    jQuery(function () {
        var documentHeight = jQuery(document).height();
        var element = jQuery('#you-element');
        var distanceFromBottom = documentHeight - (element.position().top + element.outerHeight(true));
        alert(distanceFromBottom)
    });
    

-1

Bạn có thể kiểm tra vị trí của div bằng cách sử dụng $(div).position()và kiểm tra xem thuộc tính lề trái và lề trên có nhỏ hơn 0 hay không:

if($(div).position().left < 0 && $(div).position().top < 0){
    alert("off screen");
}

2
Điều gì sẽ xảy ra nếu div không âm ngoài tầm nhìn?
dude
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.