Обнаруживать, если пользователь просмотрел div [duplicate]

Я использовал библиотеку python humanfriendly для этого, он работает очень хорошо.

import humanfriendly
from datetime import timedelta
delta = timedelta(seconds = 321)
humanfriendly.format_timespan(delta)

'5 minutes and 21 seconds'

Доступно в https://pypi.org/project/humanfriendly/

779
задан Animesh 15 June 2018 в 06:59
поделиться

22 ответа

Основываясь на решении @ dan выше ( https://stackoverflow.com/a/7557433/5628 ), у меня была задача очистки, чтобы использовать его несколько раз на одной странице проще:

$(function() {

  $(window).on('load resize scroll', function() {
    addClassToElementInViewport($('.bug-icon'), 'animate-bug-icon');
    addClassToElementInViewport($('.another-thing'), 'animate-thing');
    //                   
289
ответ дан Community 16 August 2018 в 11:56
поделиться
  • 1
    У оригинальной функции была ошибка. Необходимо сохранить ширину / высоту перед переназначением el ... – Prestaul 24 September 2008 в 03:56
  • 2
    Что, если элемент живет в прокручиваемом div и прокручивается из вида? – amartynov 6 March 2011 в 09:42
  • 3
    Просмотрите более новую версию скрипта ниже. – Dan 26 September 2011 в 16:29
  • 4
    Также интересуется вопросом @ amartynov. Кто-нибудь знает, как просто сказать, скрыт ли элемент из-за переполнения элемента-предка? Бонус, если это можно обнаружить независимо от того, насколько глубоко вложен ребенок. – Eric Nguyen 8 November 2012 в 01:51
  • 5
    @deadManN, рекурсивный через DOM, как известно, медленный. Это достаточно разумно, но разработчики браузеров также создали getBoundingClientRect специально для того, чтобы найти координаты элементов ... Почему бы нам не использовать его? – Prestaul 6 July 2015 в 15:25
  • 6
    Вы обязательно должны кэшировать $window = $(window) вне обработчика прокрутки – Adam Rehal 1 November 2017 в 09:13
290
ответ дан Community 6 September 2018 в 06:01
поделиться

Теперь большинство браузеров поддерживают метод getBoundingClientRect , который стал лучшей практикой. Использование старого ответа очень медленное , неточно и имеет несколько ошибок .

Решение, выбранное как правильное, [ почти никогда не уточняется . Вы можете прочитать о своих ошибках.


Это решение было протестировано на IE7 +, iOS5 + Safari, Android2 +, Blackberry, Opera Mobile и IE Mobile 10 .


function isElementInViewport (el) {

    //special bonus for those using jQuery
    if (typeof jQuery === "function" && el instanceof jQuery) {
        el = el[0];
    }

    var rect = el.getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
    );
}

Как использовать:

Вы можете быть уверены, что приведенная выше функция возвращает правильный ответ в момент времени, когда , но как насчет видимости элемента отслеживания как события?

Поместите следующий код внизу вашего тега <body>:

function onVisibilityChange(el, callback) {
    var old_visible;
    return function () {
        var visible = isElementInViewport(el);
        if (visible != old_visible) {
            old_visible = visible;
            if (typeof callback == 'function') {
                callback();
            }
        }
    }
}

var handler = onVisibilityChange(el, function() {
    /* your code go here */
});


//jQuery
$(window).on('DOMContentLoaded load resize scroll', handler); 

/* //non-jQuery
if (window.addEventListener) {
    addEventListener('DOMContentLoaded', handler, false); 
    addEventListener('load', handler, false); 
    addEventListener('scroll', handler, false); 
    addEventListener('resize', handler, false); 
} else if (window.attachEvent)  {
    attachEvent('onDOMContentLoaded', handler); // IE9+ :(
    attachEvent('onload', handler);
    attachEvent('onscroll', handler);
    attachEvent('onresize', handler);
}
*/

Если вы это сделаете любые модификации DOM, они могут, естественно, изменить видимость вашего элемента.

Рекомендации и распространенные ошибки:

Возможно, вам нужно отслеживать масштабирование страницы / мобильное устройство? jQuery должен обрабатывать кросс-браузер zoom / pinch , в противном случае ссылка first или second вам поможет.

Если вы измените DOM, это может повлиять на видимость элемента. Вы должны взять это под контроль и называть handler() вручную. К сожалению, у нас нет кросс-браузера onrepaint. С другой стороны, это позволяет нам делать оптимизации и выполнять повторную проверку только на модификациях DOM, которые могут изменять видимость элемента.

Никогда не использовать его внутри jQuery $ (document) .ready () , потому что в настоящий момент не была применена гарантия CSS .

После запуска DOMContentLoaded стили применяются , но ] изображения еще не загружены . Итак, мы должны добавить прослушиватель событий window.onload.

Мы еще не можем уловить событие масштабирования / пинча.

Последним средством может быть следующий код:

/* TODO: this looks like a very bad code */
setInterval(handler, 600); 

Вы можете использовать удивительную функцию pageVisibiliy API HTML5, если вам интересно, активна и видима вкладка с вашей веб-страницей.

TODO: этот метод не обрабатывает два ситуации:

1169
ответ дан 27 revs, 7 users 92% 16 August 2018 в 11:56
поделиться
  • 1
    Я использую это решение (но остерегайтесь опечатки «botom»). Также есть что-то, о чем нужно знать, когда элемент, который мы рассматриваем, будет иметь изображения. Chrome (по крайней мере) должен дождаться загрузки изображения, чтобы иметь точное значение для boundingRectangle. Кажется, что у Firefox нет этой «проблемы». – Claudio 20 October 2011 в 13:38
  • 2
    Работает ли это, когда вы включаете прокрутку в контейнере внутри тела. Например, здесь это не работает - agaase.github.io/webpages/demo/isonscreen2.html isElementInViewport (document.getElementById («innerele»)). innerele присутствует внутри контейнера, который имеет прокрутку. – agaase 8 December 2013 в 11:04
  • 3
    В расчетах предполагается, что элемент меньше экрана. Если у вас есть высокие или широкие элементы, может быть более точным использовать return (rect.bottom >= 0 && rect.right >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth)); – Roonaan 21 February 2014 в 09:29
  • 4
    Совет. Для тех, кто пытается реализовать это с помощью jQuery, просто дружественное напоминание о передаче объекта HTML DOM (например, isElementInViewport(document.getElementById('elem'))), а не объект jQuery (например, isElementInViewport($("#elem))). Эквивалент jQuery должен добавить [0] так: isElementInViewport($("#elem)[0]). – jiminy 12 April 2014 в 08:44
  • 5
    el is not defined – M_Willett 18 October 2016 в 10:47

Я считаю, что принятый ответ здесь слишком сложный для большинства случаев использования. Этот код хорошо выполняет работу (используя JQuery) и различает полностью видимые и частично видимые элементы.

var element         = $("#element");
var topOfElement    = element.offset().top;
var bottomOfElement = element.offset().top + element.outerHeight(true);
var $window         = $(window);

$window.bind('scroll', function() {

    var scrollTopPosition   = $window.scrollTop()+$window.height();
    var windowScrollTop     = $window.scrollTop()

    if( windowScrollTop > topOfElement && windowScrollTop < bottomOfElement) {
       // Element is partially visible (above viewable area)
       console.log("Element is partially visible (above viewable area)");

    }else if( windowScrollTop > bottomOfElement && windowScrollTop > topOfElement ) {
        // Element is hidden (above viewable area)
       console.log("Element is hidden (above viewable area)");

    }else if( scrollTopPosition < topOfElement && scrollTopPosition < bottomOfElement ) {
        // Element is hidden (below viewable area)
        console.log("Element is hidden (below viewable area)");

    }else if( scrollTopPosition < bottomOfElement && scrollTopPosition > topOfElement ) {
        // Element is partially visible (below viewable area)
        console.log("Element is partially visible (below viewable area)");

    }else{
        // Element is completely visible
        console.log("Element is completely visible");
    }
});
6
ответ дан Adam Rehal 16 August 2018 в 11:56
поделиться
  • 1
    Работает блестяще! Протестировано в Chrome, Firefox и Safari. – noobsharp 8 May 2016 в 14:45
  • 2
    Вы можете использовать этот . – Jonatas Walker 1 October 2016 в 12:54
  • 3
    Вы должны обязательно кэшировать $window = $(window) вне обработчика прокрутки. – sam 1 July 2017 в 19:36

Вот мое решение, оно будет работать, если элемент скрыт внутри контейнера с прокруткой.

Вот демо (попробуйте изменить размер окна)

var visibleY = function(el){
    var top = el.getBoundingClientRect().top, rect, el = el.parentNode;
    do {
        rect = el.getBoundingClientRect();
        if (top <= rect.bottom === false)
            return false;
        el = el.parentNode;
    } while (el != document.body);
    // Check its within the document viewport
    return top <= document.documentElement.clientHeight;
};

Мне нужно было проверить, видимо ли это по оси Y (для прокрутка ajax загружает больше функций записи).

1
ответ дан Ally 16 August 2018 в 11:56
поделиться

Обновить

В современных браузерах вам может понадобиться проверить API-интерфейс пересечения , который обеспечивает следующие преимущества:

  • Лучшая производительность чем прослушивание событий прокрутки
  • Работает в кросс-доменных iframe
  • Может определить, что элемент препятствует / пересекает другой

Intersection Observer находится на своем способ стать полноправным стандартом и уже поддерживается в Chrome 51+, Edge 15+ и Firefox 55+ и находится в разработке для Safari. Существует также polyfill .


Предыдущий ответ

Есть некоторые проблемы с ответом , предоставленным Dan , который может сделать его непригодным для некоторых ситуаций. Некоторые из этих проблем указаны в его ответе в нижней части, что его код даст ложные срабатывания для элементов, которые:

  • Скрыт другим элементом перед тестируемым
  • Вне видимой области элемента parent или ancestor
  • Элемент или его дочерние элементы скрыты с помощью свойства CSS clip

Эти ограничения демонстрируются в следующих результатах простого теста :

Failed test, using isElementInViewport [/g11]

Решение: isElementVisible()

Вот решение этих проблем, с приведенным ниже результатом теста и объяснением некоторых частей кода.

function isElementVisible(el) {
    var rect     = el.getBoundingClientRect(),
        vWidth   = window.innerWidth || doc.documentElement.clientWidth,
        vHeight  = window.innerHeight || doc.documentElement.clientHeight,
        efp      = function (x, y) { return document.elementFromPoint(x, y) };     

    // Return false if it's not in the viewport
    if (rect.right < 0 || rect.bottom < 0 
            || rect.left > vWidth || rect.top > vHeight)
        return false;

    // Return true if any of its four corners are visible
    return (
          el.contains(efp(rect.left,  rect.top))
      ||  el.contains(efp(rect.right, rect.top))
      ||  el.contains(efp(rect.right, rect.bottom))
      ||  el.contains(efp(rect.left,  rect.bottom))
    );
}

Тест прохождения: http://jsfiddle.net/AndyE / cAY8c /

И результат:

Passed test, using isElementVisible [/g12]

Дополнительные примечания

[ Однако этот метод не лишен собственных ограничений. Например, проверяемый элемент с более низким z-индексом, чем другой элемент в том же месте, будет идентифицирован как скрытый, даже если элемент впереди фактически не скрывает какой-либо его части. Тем не менее, этот метод имеет свои применения в некоторых случаях, когда решение Дэна не распространяется.

Оба element.getBoundingClientRect() и document.elementFromPoint() являются частью спецификации рабочего проекта CSSOM и поддерживаются, по крайней мере, в IE 6 и позже и большинство настольных браузеров в течение длительного времени (хотя и не совсем). См. Quirksmode для этих функций для получения дополнительной информации.

contains() используется, чтобы увидеть, является ли элемент, возвращаемый document.elementFromPoint() дочерним узлом тестируемого элемента для видимость. Он также возвращает true, если возвращаемый элемент является одним и тем же элементом. Это просто делает проверку более надежной. Он поддерживается во всех основных браузерах, Firefox 9.0 является последним из них, чтобы добавить его. Для более старой поддержки Firefox проверьте историю этого ответа.

Если вы хотите проверить больше точек вокруг элемента для видимости, т. Е. Убедиться, что элемент не покрыт более, чем, скажем, 50% это не займет много времени, чтобы отрегулировать последнюю часть ответа. Однако имейте в виду, что это, вероятно, будет очень медленным, если вы проверили каждый пиксель, чтобы убедиться, что он был на 100% видимым.

124
ответ дан Andy E 16 August 2018 в 11:56
поделиться
  • 1
    Вы имели в виду использовать doc.documentElement.clientWidth? Должен ли это быть «document.documentElement» вместо этого? С другой стороны, это единственный метод, который также работает для использования таких случаев, как скрытие содержимого элемента для доступности с помощью свойства CSS clip: snook.ca/archives/html_and_css/hiding-content-for- доступность – klamping 19 March 2013 в 21:34
  • 2
    @klamping: хороший улов, спасибо. Я скопировал его прямо из моего кода, где я использовал doc как псевдоним для document. Да, мне нравится думать об этом как о достойном решении для краевых дел. – Andy E 19 March 2013 в 22:14
  • 3
    Для меня это не работает. Но inViewport () в предыдущем ответе работает в FF. – Satya Prakash 28 December 2013 в 09:05
  • 4
    Также может быть полезно проверить, что центр элемента виден, если у вас есть закругленные углы или примененное преобразование, поскольку ограничивающие углы не могут возвращать ожидаемый элемент: element.contains(efp(rect.right - (rect.width / 2), rect.bottom - (rect.height / 2))) – Jared 10 March 2015 в 09:15
  • 5
    Не работал на входы для меня (хром канарейки 50). Не знаете, почему, возможно, родные круговые углы? Мне пришлось немного уменьшить координаты, чтобы заставить работать el.contains (efp (rect.left + 1, rect.top + 1)) || el.contains (efp (rect.right-1, rect.top + 1)) || el.contains (efp (rect.right-1, rect.bottom-1)) || el.contains (efp (rect.left + 1, rect.bottom-1)) – Rayjax 18 February 2016 в 15:05

Легкое и маленькое решение, которое сработало для меня.

Пример. Вы хотите увидеть, является ли элемент видимым в родительском элементе с переполнением переполнения.

$(window).on('scroll', function () {  

     var container = $('#sidebar');
     var containerHeight = container.height();
     var scrollPosition = $('#row1').offset().top - container.offset().top;

     if (containerHeight < scrollPosition) {
         console.log('not visible');
     } else {
         console.log('visible');
     }
})
0
ответ дан Dave 16 August 2018 в 11:56
поделиться

Все ответы, которые я встречал здесь, проверяют только, находится ли элемент внутри текущего видового экрана. Но это не значит, что это видно. Что, если данный элемент находится внутри div с переполненным контентом, и он прокручивается вне поля зрения?

Чтобы решить эту проблему, вам нужно будет проверить, содержится ли этот элемент всеми родителями. Мое решение делает именно это:

Он также позволяет вам указать, какая часть элемента должна быть видимой.

Element.prototype.isVisible = function(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 = this.getBoundingClientRect();
    var parentRects = [];
    var element = this;

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

Это решение игнорировало тот факт, что элементы могут быть не видны из-за других фактов, таких как opacity: 0.

Я тестировал это решение в Chrome и Internet Explorer 11.

2
ответ дан Domysee 16 August 2018 в 11:56
поделиться

моя более короткая и быстрая версия.

function isElementOutViewport (el) {
    var rect = el.getBoundingClientRect();
    return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}

добавить jsFiddle по необходимости https://jsfiddle.net/on1g619L/1/

18
ответ дан Eric Chen 16 August 2018 в 11:56
поделиться

Проверяет, является ли элемент хотя бы частично отображаемым (вертикальный размер):

function inView(element) {
                var box = element.getBoundingClientRect();
                return inViewBox(box);
}

function inViewBox(box) {
                return ((box.bottom < 0) || (box.top > getWindowSize().h)) ? false : true;
}


function getWindowSize() { 
        return { w: document.body.offsetWidth || document.documentElement.offsetWidth || window.innerWidth, h: document.body.offsetHeight || document.documentElement.offsetHeight || window.innerHeight} 
}
0
ответ дан Lumic 16 August 2018 в 11:56
поделиться

Для подобной задачи я действительно наслаждался этим gist , который предоставляет полипол для scrollIntoViewIfNeeded () .

Все необходимые Кунг-фу должны были ответить находится внутри этого блока:

var parent = this.parentNode,
    parentComputedStyle = window.getComputedStyle(parent, null),
    parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
    parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
    overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
    overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
    overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
    overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
    alignWithTop = overTop && !overBottom;

this относится к элементу, который вы хотите знать, если он есть overTop или overBottom - просто должен получить дрейф ...

-2
ответ дан Philzen 16 August 2018 в 11:56
поделиться

Я нашел, что это беспокоит, что нет доступной функциональности jQuery. Когда я натолкнулся на решение Dan , я попробовал предоставить что-то для людей, которые любят программировать в стиле jQuery OO. Обязательно прокрутите вверх и оставьте верх над кодом Дэна.

bada bing bada boom

$.fn.inView = function(){
    if(!this.length) return false;
    var rect = this.get(0).getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );

};

//additional examples for other use cases
//true false whether an array of elements are all in view
$.fn.allInView = function(){
    var all = [];
    this.forEach(function(){
        all.push( $(this).inView() );
    });
    return all.indexOf(false) === -1;
};

//only the class elements in view
$('.some-class').filter(function(){
    return $(this).inView();
});

//only the class elements not in view
$('.some-class').filter(function(){
    return !$(this).inView();
});

использование

$(window).on('scroll',function(){ 

    if( $('footer').inView() ) {
        // do cool stuff
    }

});
19
ответ дан r3wt 16 August 2018 в 11:56
поделиться
  • 1
    Будет ли фигурная скобка достаточной для закрытия утверждения if? – calasyr 24 May 2016 в 23:58
  • 2
    Я не мог заставить его работать с несколькими элементами одинакового класса. – The Whiz of Oz 20 June 2017 в 07:38
  • 3
    @TheWhizofOz Я обновил свой ответ, чтобы привести примеры других возможных случаев использования, которые вы подняли. удачи. – r3wt 20 June 2017 в 20:07

Лучшее решение:

function getViewportSize(w) {
    var w = w || window;
    if(w.innerWidth != null) return {w:w.innerWidth, h:w.innerHeight};
    var d = w.document;
    if (document.compatMode == "CSS1Compat") {
        return {
            w: d.documentElement.clientWidth,
            h: d.documentElement.clientHeight
        };
    }
    return { w: d.body.clientWidth, h: d.body.clientWidth };
}
function isViewportVisible(e) {
    var box = e.getBoundingClientRect();
    var height = box.height || (box.bottom - box.top);
    var width = box.width || (box.right - box.left);
    var viewport = getViewportSize();
    if(!height || !width) return false;
    if(box.top > viewport.h || box.bottom < 0) return false;
    if(box.right < 0 || box.left > viewport.w) return false;
    return true;    
}
0
ответ дан rainyjune 16 August 2018 в 11:56
поделиться
  • 1
    Вы должны попытаться объяснить, почему ваша версия лучше. Как бы то ни было, он выглядит примерно так же, как и другие решения. – Andy E 4 March 2013 в 15:46
  • 2
    Отличное решение имеет BOX / ScrollContainer и не использует WINDOW (только если его не указано). Взгляните на код, чем на то, что это более универсальное решение (искал его много) – teter 13 May 2015 в 09:10

Зависит от того, что вы подразумеваете под видимым. Если вы имеете в виду, это в настоящее время отображается на странице, учитывая положение прокрутки, вы можете рассчитать ее на основе смещений элементов y и текущей позиции прокрутки.

2
ответ дан roryf 16 August 2018 в 11:56
поделиться

См. источник грани , который использует getBoundingClientRect . Это как:

function inViewport (el) {

    var r, html;
    if ( !el || 1 !== el.nodeType ) { return false; }
    html = document.documentElement;
    r = el.getBoundingClientRect();

    return ( !!r 
      && r.bottom >= 0 
      && r.right >= 0 
      && r.top <= html.clientHeight 
      && r.left <= html.clientWidth 
    );

}

Возвращает true, если какая-либо часть элемента находится в окне просмотра.

23
ответ дан ryanve 16 August 2018 в 11:56
поделиться

Я использую эту функцию (она только проверяет, является ли y незашифрованным, поскольку большую часть времени x не требуется)

function elementInViewport(el) {
    var elinfo = {
        "top":el.offsetTop,
        "height":el.offsetHeight,
    };

    if (elinfo.top + elinfo.height < window.pageYOffset || elinfo.top > window.pageYOffset + window.innerHeight) {
        return false;
    } else {
        return true;
    }

}
-1
ответ дан sanderjonk01 16 August 2018 в 11:56
поделиться

Как публичная служба: ответ Дэна с правильными вычислениями (элемент может быть> окном, особенно на экранах мобильных телефонов), и исправление jQuery-тестирования, а также добавление isElementPartiallyInViewport:

Кстати, разница между window.innerWidth и document.documentElement.clientWidth заключается в том, что clientWidth / clientHeight не включает полосу прокрутки, тогда как window.innerWidth / Height делает.

function isElementPartiallyInViewport(el)
{
    //special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

    var rect = el.getBoundingClientRect();
    // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
    var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
    var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

    return (vertInView && horInView);
}


// http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
function isElementInViewport (el) 
{
    //special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

    var rect = el.getBoundingClientRect();
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    return (
           (rect.left >= 0)
        && (rect.top >= 0)
        && ((rect.left + rect.width) <= windowWidth)
        && ((rect.top + rect.height) <= windowHeight)
    );

}


function fnIsVis(ele)
{
    var inVpFull = isElementInViewport(ele);
    var inVpPartial = isElementPartiallyInViewport(ele);
    console.clear();
    console.log("Fully in viewport: " + inVpFull);
    console.log("Partially in viewport: " + inVpPartial);
}

Test -case

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Test</title>
    <!--
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>    
    <script src="scrollMonitor.js"></script>
    -->

    <script type="text/javascript">

        function isElementPartiallyInViewport(el)
        {
            //special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

            var rect = el.getBoundingClientRect();
            // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
            var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
            var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

            return (vertInView && horInView);
        }


        // http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
        function isElementInViewport (el) 
        {
            //special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];


            var rect = el.getBoundingClientRect();
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            return (
                   (rect.left >= 0)
                && (rect.top >= 0)
                && ((rect.left + rect.width) <= windowWidth)
                && ((rect.top + rect.height) <= windowHeight)
            );

        }


        function fnIsVis(ele)
        {
            var inVpFull = isElementInViewport(ele);
            var inVpPartial = isElementPartiallyInViewport(ele);
            console.clear();
            console.log("Fully in viewport: " + inVpFull);
            console.log("Partially in viewport: " + inVpPartial);
        }


        // var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft,
        // var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;

    </script>

</head>
<body>

    <div style="display: block; width: 2000px; height: 10000px; background-color: green;">

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <div style="background-color: crimson; display: inline-block; width: 800px; height: 500px;" ></div>
        <div id="myele" onclick="fnIsVis(this);" style="display: inline-block; width: 100px; height: 100px; background-color: hotpink;">
        t
        </div>

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

    </div>

    <!--
    <script type="text/javascript">

        var element = document.getElementById("myele");
        var watcher = scrollMonitor.create( element );

        watcher.lock();

        watcher.stateChange(function() {
            console.log("state changed");
            // $(element).toggleClass('fixed', this.isAboveViewport)
        });

    </script>
    -->
</body>
</html>
25
ответ дан Stefan Steiger 16 August 2018 в 11:56
поделиться
  • 1
    isElementPartiallyInViewport очень полезен. Хороший. – RJ Cuthbertson 28 October 2015 в 14:02
  • 2
    Для isElementInViewport (e): ваш код даже не загружает изображения. Это верно: function isElementInViewport (e) {var t = e.getBoundingClientRect (); return t.top & gt; = 0 & amp; & amp; t.left & gt; = 0 & amp; & amp; t.bottom & lt; = (window.innerHeight || document.documentElement.clientHeight) & amp; & amp; & amp; & amp; & amp; t.right & lt; = (window.innerWidth || document.documentElement.clientWidth)} – Arun chauhan 13 August 2018 в 08:00
  • 3
    @Arun chauhan: Ни один из моих кодов не загружает изображения, поэтому зачем это делать, а формула правильная. – Stefan Steiger 13 August 2018 в 08:53

Я думаю, что это более функциональный способ сделать это. Ответы Дэна не работают в рекурсивном контексте.

Эта функция решает проблему, когда ваш элемент находится внутри других прокручиваемых divs, проверяя любые уровни, рекурсивно верхние к тегу HTML, и останавливается в первом false.

/**
 * fullVisible=true only returns true if the all object rect is visible
 */
function isReallyVisible(el, fullVisible) {
    if ( el.tagName == "HTML" )
            return true;
    var parentRect=el.parentNode.getBoundingClientRect();
    var rect = arguments[2] || el.getBoundingClientRect();
    return (
            ( fullVisible ? rect.top    >= parentRect.top    : rect.bottom > parentRect.top ) &&
            ( fullVisible ? rect.left   >= parentRect.left   : rect.right  > parentRect.left ) &&
            ( fullVisible ? rect.bottom <= parentRect.bottom : rect.top    < parentRect.bottom ) &&
            ( fullVisible ? rect.right  <= parentRect.right  : rect.left   < parentRect.right ) &&
            isReallyVisible(el.parentNode, fullVisible, rect)
    );
};
3
ответ дан ton 16 August 2018 в 11:56
поделиться

Я попробовал ответ Дэна , но алгебра, используемая для определения границ, неверна. Ответ ryanve ближе, но проверяемый элемент должен находиться внутри области просмотра по крайней мере на 1 пиксель, поэтому попробуйте эту функцию:

function isElementInViewport(el) {
    var rect = el.getBoundingClientRect();

    return rect.bottom > 0 &&
        rect.right > 0 &&
        rect.left < (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ &&
        rect.top < (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */;
}
44
ответ дан Walf 16 August 2018 в 11:56
поделиться

У меня был тот же вопрос, и я понял, используя getBoundingClientRect (). Этот код полностью «общий» и должен быть написан только один раз для его работы (вам не нужно записывать его для каждого элемента, который вы хотите знать, в окне просмотра). Этот код проверяет, не вертикально ли он в вертикальном направлении, а не по горизонтали. В этом случае переменные (массивы) «элементы» содержат все элементы, которые вы проверяете, чтобы они были вертикально в окне просмотра, поэтому хватайте любые элементы, которые вы хотите где угодно, и храните их там. Цикл «for» циклически проходит через каждый элемент и проверяет, находится ли он вертикально в окне просмотра. Этот код выполняется каждый раз, когда пользователь прокручивается! Если верхняя часть getBoudingClientRect () меньше 3/4, то окно просмотра (элемент составляет одну четверть в окне просмотра), он регистрируется как «в окне просмотра». Поскольку код является общим, вам нужно знать, какой элемент находится в окне просмотра. Чтобы узнать это, вы можете определить его по пользовательскому атрибуту, имени узла, идентификатору, имени класса и т. Д. Вот мой код (скажите, если он не работает, он был протестирован в IE 11, FireFox 40.0.3, Chrome версии 45.0.2454.85 m, Opera 31.0.1889.174 и Edge с Windows 10, [еще не Safari] ) ...

//scrolling handlers...
window.onscroll = function(){
  var elements = document.getElementById('whatever').getElementsByClassName('whatever');
  for(var i = 0; i != elements.length; i++)
  {
   if(elements[i].getBoundingClientRect().top <= window.innerHeight*0.75 && elements[i].getBoundingClientRect().top > 0)
   {
      console.log(elements[i].nodeName + ' ' + elements[i].className + ' ' + elements[i].id + ' is in the viewport; proceed with whatever code you want to do here.');
   }
};

Надеюсь, это поможет кому-то: -)

0
ответ дан www139 16 August 2018 в 11:56
поделиться

Существует плагин jQuery под названием inview , который выполняет задание

25
ответ дан Yuri Salimovskiy 16 August 2018 в 11:56
поделиться
0
ответ дан ssten 29 October 2018 в 12:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: