javascript - top - scroll slow jquery




Compruebe si el elemento es visible después de desplazarse (20)

Adapté esta corta extensión de la función jQuery, que puedes usar libremente (licencia 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));
};

Estoy cargando elementos a través de AJAX. Algunos de ellos solo son visibles si se desplaza hacia abajo en la página.
¿Hay alguna manera de saber si un elemento está ahora en la parte visible de la página?


Aprovechando esta gran respuesta , puede simplificarla un poco más con ES2015 +:

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

Si no te importa que la ventana salga por la ventana y te importa que se haya visto la parte inferior, esto se puede simplificar para

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

o incluso el de una sola línea

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

Aquí hay otra solución de 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 en JSFiddle


Aquí hay una manera de lograr lo mismo usando Mootools, en horizontal, vertical o ambos.

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

El plugin jQuery Waypoints va muy bien aquí.

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

Hay algunos ejemplos en el sitio del complemento .


El uso de la nueva API IntersectionObserver es muy fácil y eficiente para determinar si un elemento es visible en la ventana gráfica. Al usar un observador , elimina la necesidad de adjuntar un evento de scroll y verificar manualmente la devolución de llamada del evento.

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

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

Ver tabla de compatibilidad de navegadores (no se admite en IE / Safari)


Este método devolverá verdadero si alguna parte del elemento está visible en la página. Funcionó mejor en mi caso y puede ayudar a alguien más.

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

Esto considera cualquier relleno, borde o margen que tenga el elemento, así como elementos más grandes que la propia ventana gráfica.

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

Para llamarlo usa algo como esto:

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

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

Hay un complemento para jQuery llamado inview que agrega un nuevo evento "inview".

Aquí hay algo de código para un complemento de jQuery que no usa eventos:

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

Encontré esto en un comentario aquí ( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ ) por un tipo llamado James


He escrito un componente para la tarea, diseñado para manejar grandes cantidades de elementos extremadamente rápido (con una melodía de <10 ms para 1000 elementos en un móvil lento ).

Funciona con cada tipo de contenedor de desplazamiento al que tiene acceso (ventana, elementos HTML, iframe incorporado, ventana secundaria generada) y es muy flexible en lo que detecta ( visibilidad total o parcial , cuadro de borde o cuadro de contenido , zona de tolerancia personalizada, etc ).

Un enorme conjunto de pruebas, en su mayoría autogenerados, garantiza que funcione como se anuncia cross-browser .

Dale una oportunidad si te gusta: jQuery.isInView . De lo contrario, podría encontrar inspiración en el código fuente, por ejemplo, here .


La mayoría de las respuestas aquí no tienen en cuenta que un elemento también se puede ocultar porque está desplazado fuera de la vista de un div, no solo de toda la página.

Para cubrir esa posibilidad, básicamente tienes que verificar si el elemento está ubicado dentro de los límites de cada uno de sus padres.

Esta solución hace exactamente eso:

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

También le permite especificar a qué porcentaje debe estar visible en cada dirección.
No cubre la posibilidad de que pueda estar oculto debido a otros factores, como display: hidden .

Esto debería funcionar en todos los navegadores principales, ya que solo usa getBoundingClientRect . Yo personalmente lo probé en Chrome e Internet Explorer 11.


Modificación simple para div desplazable (contenedor)

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

NOTA: esto no funciona si el elemento es más grande que el div desplazable.


Prefiero usar jQuery expr

jQuery.extend(jQuery.expr[':'], {  
    inview: function (elem) {
        var t = $(elem);
        var offset = t.offset();
        var win = $(window); 
        var winST = win.scrollTop();
        var elHeight = t.outerHeight(true);

        if ( offset.top > winST - elHeight && offset.top < winST + elHeight + win.height()) {
            return true;    
        }    
        return false;  
    }
});

para que puedas usarlo de esta manera

$(".my-elem:inview"); //returns only element that is in view
$(".my-elem").is(":inview"); //check if element is in view
$(".my-elem:inview").length; //check how many elements are in view

Puede agregar fácilmente dicho código dentro de la función de evento de scroll , etc. para verificarlo cada vez que el usuario desplace la vista.


Puede utilizar el complemento jquery "onScreen" para verificar si el elemento se encuentra en la vista actual cuando se desplaza. El complemento establece el ": onScreen" del selector en verdadero cuando el selector aparece en la pantalla. Este es el enlace para el complemento que puede incluir en su proyecto. " http://benpickles.github.io/onScreen/jquery.onscreen.min.js "

Puedes probar el siguiente ejemplo que funciona para mí.

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

Código 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;
}

Se modificó la respuesta aceptada para que el elemento tenga que tener su propiedad de visualización establecida en algo distinto de "ninguno" para que la calidad sea visible.

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

Si desea modificar esto para el elemento de desplazamiento dentro de otro 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)); 
}

Un ejemplo basado en esta respuesta para verificar si un elemento es 75% visible (es decir, menos del 25% está fuera de la pantalla).

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

Vainilla simple para verificar si el elemento ( el ) es visible en div desplazable ( 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
},

Uso con jQuery:

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

isScrolledIntoView es una función muy necesaria, así que la probé, funciona para elementos que no son más altos que la ventana gráfica, pero si el elemento es más grande que la ventana gráfica no funciona. Para solucionar este problema fácilmente cambiar la condición

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

a esto:

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

Vea la demostración aquí: http://jsfiddle.net/RRSmQ/


Esta respuesta en vainilla:

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




scroll