Jak sprawdzić, czy element jest poza ekranem

81

Muszę sprawdzić w jQuery, czy element DIV nie spada poza ekran. Elementy są widoczne i wyświetlane zgodnie z atrybutami CSS, ale można je celowo umieścić poza ekranem poprzez:

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

Nie mogłem użyć :visibleselektora jQuery , ponieważ element ma niezerową wysokość i szerokość.

Nie robię nic wymyślnego. To absolutne umieszczenie pozycji jest sposobem, w jaki mój framework Ajax implementuje ukrywanie / pokazywanie niektórych widżetów.

Maks
źródło
Odpowiedziałem również na to pytanie „duplikat”: stackoverflow.com/questions/5353934/…
Tokimon

Odpowiedzi:

136

Zależy od tego, jaka jest Twoja definicja pojęcia „poza ekranem”. Czy to jest w widocznym obszarze, czy w określonych granicach twojej strony?

Używając Element.getBoundingClientRect () możesz łatwo wykryć, czy twój element znajduje się w granicach twojego widocznego obszaru (tj. Na ekranie lub poza ekranem):

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

Możesz wtedy użyć tego na kilka sposobów:

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

// boolean returned if element is offscreen
$('div').is(':offscreen');
scurker
źródło
2
Podobało mi się to, ale psuje się, jeśli twój element znajduje się wewnątrz przewijalnego kontenera - element na dole 2-ekranowego DIV zawsze będzie „poza ekranem”, ponieważ wysokość okna jest mniejsza niż offsetTop elementu.
Coderer
@scurker Nie udało mi się to uruchomić. Oto moje pytanie SO (z jsFiddle) dotyczące problemu: stackoverflow.com/questions/26004098/ ...
crashwap
Czy nie mylę się, sądząc, że tak się nie stanie, jeśli el umieścił rodzica (absolutnego lub względnego) przed ciałem?
fekiri malek
@fekirimalek Masz rację, zaktualizowałem przykład, aby to uwzględnić
scurker
7
Zauważ, że obecnie (styczeń 2017) to nie będzie działać przynajmniej w Chrome, ponieważ Element.getBoundingClientRect () ma właściwości top, right, bottom i left zamiast x i y.
Asu
18

Jest tutaj wtyczka jQuery, która pozwala użytkownikom sprawdzić, czy element mieści się w widocznym obszarze przeglądarki, biorąc pod uwagę pozycję przewijania przeglądarki.

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

Możesz również sprawdzić częściową widoczność:

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

Jedną wadą jest to, że działa tylko z pozycjonowaniem / przewijaniem w pionie, chociaż dodanie pozycjonowania poziomego do miksu powinno być dość łatwe.

Sam Sehnert
źródło
To jest BARDZO lekka wtyczka. Udało mi się uzyskać stały pasek nawigacyjny podczas przewijania w górę i działający szybko w ciągu kilku minut od dodania. Świetna sugestia.
Nappstir
Ta wtyczka jest bardzo lekka i dość łatwa do wdrożenia. Rozwiązano problem z podmenu.
Theo Orphanos
9

Nie ma potrzeby używania wtyczki, aby sprawdzić, czy jest poza portem widoku.

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))
    }
});
Simon Hudin
źródło
1
To zadziała, jeśli użyjesz $(this).offsetzamiast $this.position. W tej chwili oblicza tylko odległość od swojego rodzica, który może być elementem div, który idealnie go otacza.
Ryan Shillington
7

Cóż ... znalazłem kilka problemów w każdym proponowanym tutaj rozwiązaniu.

  • Powinieneś móc wybrać, czy chcesz, aby cały element był na ekranie, czy tylko jakakolwiek jego część
  • Proponowane rozwiązania zawodzą, jeśli element jest wyższy / szerszy niż okno i trochę zakrywa okno przeglądarki.

Oto moje rozwiązanie, które obejmuje jQuery .fnfunkcję instancji iexpression . Utworzyłem więcej zmiennych w mojej funkcji, niż mogłem, ale w przypadku złożonego problemu logicznego lubię podzielić ją na mniejsze, wyraźnie nazwane części.

Używam getBoundingClientRectmetody, która zwraca pozycję elementu względem widoku, więc nie muszę przejmować się pozycją przewijania

Zastosowanie :

$(".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 

Źródło :

$.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);
};
Adam Pietrasiak
źródło
1
Otrzymuję make_footer_down.js: 8 Uncaught TypeError: Nie można odczytać właściwości „getBoundingClientRect” o wartości undefined podczas próby użycia tam funkcji ur.
Ludvig W
Cześć Lurr ... Próbowałem z $ ("# divId"). IsOnScreen (true); gdzie „divId” był poza ekranem i zwrócił mi „false”; więc czuję, że to działa
Anirban
1
  • Uzyskaj odległość od góry danego elementu
  • Dodaj wysokość tego samego podanego elementu. To powie Ci całkowitą liczbę od góry ekranu do końca danego elementu.
  • Następnie wszystko, co musisz zrobić, to odjąć to od całkowitej wysokości dokumentu

    jQuery(function () {
        var documentHeight = jQuery(document).height();
        var element = jQuery('#you-element');
        var distanceFromBottom = documentHeight - (element.position().top + element.outerHeight(true));
        alert(distanceFromBottom)
    });
    
user5294803
źródło
-1

Możesz sprawdzić pozycję div za pomocą $(div).position()i sprawdzić, czy właściwości lewego i górnego marginesu są mniejsze niż 0:

if($(div).position().left < 0 && $(div).position().top < 0){
    alert("off screen");
}
Troy Barlow
źródło
2
A jeśli div nie jest ujemny?
koleś