Обнаруживать, когда элементы в прокручиваемом div не отображаются
Мне нужно найти хорошее решение для следующей проблемы. Я вижу, что многие люди спрашивают о отслеживании, находится ли элемент в или за пределами порта "Порт" для окна страницы или браузера. Мне нужно реплицировать это действие, но внутри DIV, который прокручивается, с переполнением: например, прокрутка. Кто-нибудь знает хороший пример для этого конкретного действия?
Спасибо заранее.
Ответы
Ответ 1
У меня была такая же проблема раньше, у меня закончилась следующая функция. Первый параметр предназначен для проверки элемента, второй - для проверки того, частично ли элемент просматривается. Он предназначен только для вертикальной проверки, вы можете расширить его, чтобы проверить горизонтальную прокрутку.
function checkInView(elem,partial)
{
var container = $(".scrollable");
var contHeight = container.height();
var contTop = container.scrollTop();
var contBottom = contTop + contHeight ;
var elemTop = $(elem).offset().top - container.offset().top;
var elemBottom = elemTop + $(elem).height();
var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;
return isTotal || isPart ;
}
проверьте его на jsFiddle.
Ответ 2
Вот чистая версия принятого ответа в javascript, не полагаясь на jQuery и с некоторыми исправлениями на частичное обнаружение и поддержку сверху вниз.
function checkInView(container, element, partial) {
//Get container properties
let cTop = container.scrollTop;
let cBottom = cTop + container.clientHeight;
//Get element properties
let eTop = element.offsetTop;
let eBottom = eTop + element.clientHeight;
//Check if in view
let isTotal = (eTop >= cTop && eBottom <= cBottom);
let isPartial = partial && (
(eTop < cTop && eBottom > cTop) ||
(eBottom > cBottom && eTop < cBottom)
);
//Return outcome
return (isTotal || isPartial);
}
И в качестве бонуса эта функция гарантирует, что элемент находится в поле зрения, если он не является (частичным или полным):
function ensureInView(container, element) {
//Determine container top and bottom
let cTop = container.scrollTop;
let cBottom = cTop + container.clientHeight;
//Determine element top and bottom
let eTop = element.offsetTop;
let eBottom = eTop + element.clientHeight;
//Check if out of view
if (eTop < cTop) {
container.scrollTop -= (cTop - eTop);
}
else if (eBottom > cBottom) {
container.scrollTop += (eBottom - cBottom);
}
}
Ответ 3
Вот чистое решение для JavaScript.
function elementIsVisible(element, container, partial) {
var contHeight = container.offsetHeight,
elemTop = offset(element).top - offset(container).top,
elemBottom = elemTop + element.offsetHeight;
return (elemTop >= 0 && elemBottom <= contHeight) ||
(partial && ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= contHeight)))
}
// checks window
function isWindow( obj ) {
return obj != null && obj === obj.window;
}
// returns corresponding window
function getWindow( elem ) {
return isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
}
// taken from jquery
// @returns {{top: number, left: number}}
function offset( elem ) {
var docElem, win,
box = { top: 0, left: 0 },
doc = elem && elem.ownerDocument;
docElem = doc.documentElement;
if ( typeof elem.getBoundingClientRect !== typeof undefined ) {
box = elem.getBoundingClientRect();
}
win = getWindow( doc );
return {
top: box.top + win.pageYOffset - docElem.clientTop,
left: box.left + win.pageXOffset - docElem.clientLeft
};
};
Ответ 4
На основе лучшего ответа. Вместо того, чтобы просто сказать вам, если элемент частично видимый или нет. Я добавил немного дополнительного, чтобы вы могли передать процент (0-100), который говорит вам, если элемент больше, чем x%.
function (container, element, partial) {
var cTop = container.scrollTop;
var cBottom = cTop + container.clientHeight;
var eTop = element.offsetTop;
var eBottom = eTop + element.clientHeight;
var isTotal = (eTop >= cTop && eBottom <= cBottom);
var isPartial;
if (partial === true) {
isPartial = (eTop < cTop && eBottom > cTop) || (eBottom > cBottom && eTop < cBottom);
} else if(typeof partial === "number"){
if (eTop < cTop && eBottom > cTop) {
isPartial = ((eBottom - cTop) * 100) / element.clientHeight > partial;
} else if (eBottom > cBottom && eTop < cBottom){
isPartial = ((cBottom - eTop) * 100) / element.clientHeight > partial;
}
}
return (isTotal || isPartial);
}
Ответ 5
Я смог сделать эту работу, внеся небольшое изменение в опубликованную версию чистого JavaScript
function checkInView(container, element, partial) {
//Get container properties
let cTop = container.scrollTop;
let cBottom = cTop + container.clientHeight;
//Get element properties
let eTop = element.offsetTop - container.offsetTop; // change here
let eBottom = eTop + element.clientHeight;
//Check if in view
let isTotal = (eTop >= cTop && eBottom <= cBottom);
let isPartial = partial && (
(eTop < cTop && eBottom > cTop) ||
(eBottom > cBottom && eTop < cBottom)
);
//Return outcome
return (isTotal || isPartial);
}
Ответ 6
Я сделал плагин jquery с последним ответом:
(function($) {
$.fn.reallyVisible = function(opt) {
var options = $.extend({
cssChanges:[
{ name : 'visibility', states : ['hidden','visible'] }
],
childrenClass:'mentioners2',
partialview : true
}, opt);
var container = $(this);
var contHeight;
var contTop;
var contBottom;
var _this = this;
var _children;
this.checkInView = function(elem,partial){
var elemTop = $(elem).offset().top - container.offset().top;
var elemBottom = elemTop + $(elem).height();
var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;
return isTotal || isPart ;
}
this.bind('restoreProperties',function(){
$.each(_children,function(i,elem){
$.each(options.cssChanges,function(i,_property){
$(elem).css(_property.name,_property.states[1]);
});
});
_children = null;
});
return this.each(function(){
contHeight = container.height();
contTop = container.scrollTop();
contBottom = contTop + contHeight ;
_children = container.children("."+options.childrenClass);
$.each(_children,function(i,elem){
var res = _this.checkInView(elem,options.partialview);
if( !res ){
$.each(options.cssChanges,function(i,_property){
$(elem).css(_property.name,_property.states[0]);
});
}
});
});
}
})(jQuery);
Ответ 7
Вы можете попробовать это
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + window.innerHeight;
var el = $(elem);
var elemTop = el.offset().top;
var elemBottom = elemTop + el.height();
var elemDisplayNotNone = el.css("display") !== "none";
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop) && elemDisplayNotNone);
}
например:
isScrolledIntoView('#button')