Bir DOM öğesinin (HTML belgesinde) şu anda görünür olup olmadığını ( görünüm penceresinde görünür) anlamanın etkili bir yolu var mı ?
(Soru Firefox ile ilgilidir.)
Bir DOM öğesinin (HTML belgesinde) şu anda görünür olup olmadığını ( görünüm penceresinde görünür) anlamanın etkili bir yolu var mı ?
(Soru Firefox ile ilgilidir.)
Yanıtlar:
Güncelleme: Zaman ilerliyor ve böylece tarayıcılarımız var. Bu teknik artık önerilmemektedir ve 7'den önce Internet Explorer sürümünü desteklemeniz gerekmiyorsa Dan'ın çözümünü kullanmalısınız .
Orijinal çözüm (şimdi modası geçmiş):
Bu, öğenin geçerli görünüm penceresinde tamamen görünür olup olmadığını kontrol eder:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
Bunu, öğenin herhangi bir bölümünün görünüm alanında görünür olup olmadığını belirlemek için değiştirebilirsiniz:
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
getBoundingClientRect
özellikle eleman koordinatları bulmak amacıyla oluşturdular ... Neden kullanmıyoruz?
Artık çoğu tarayıcı , en iyi uygulama haline gelen getBoundingClientRect yöntemini destekliyor . Eski bir cevap kullanmak çok yavaş , doğru değil ve birkaç hata var .
Doğru olarak seçilen çözelti neredeyse hiçbir zaman kesin değildir . Sen edebilirsiniz devamı olan hatalar hakkında.
Bu çözüm Internet Explorer 7 (ve üstü), iOS 5 (ve üstü) Safari, Android 2.0 (Eclair) ve üstü, BlackBerry, Opera Mobile ve Internet Explorer Mobile 9'da test edildi .
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() */
);
}
Yukarıda verilen işlevin çağrıldığı anda doğru yanıtı döndürdüğünden emin olabilirsiniz, ancak bir öğenin olay olarak görünürlüğünü izlemeye ne dersiniz?
Aşağıdaki kodu <body>
etiketinizin altına yerleştirin :
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); // Internet Explorer 9+ :(
attachEvent('onload', handler);
attachEvent('onscroll', handler);
attachEvent('onresize', handler);
}
*/
Herhangi bir DOM değişikliği yaparsanız, öğenizin elbette görünürlüğünü değiştirebilirler.
Yönergeler ve yaygın tuzaklar:
Belki sayfa yakınlaştırma / mobil cihaz tutam izlemeniz gerekir? jQuery yakınlaştırma / sıkıştırma çapraz tarayıcıyı işlemelidir , aksi takdirde birinci veya ikinci bağlantı size yardımcı olacaktır.
Eğer varsa DOM'da değişiklik , bu öğenin görünürlüğünü etkileyebilir. Bunu kontrol etmeli ve handler()
manuel olarak aramalısınız . Ne yazık ki, çapraz tarayıcı onrepaint
etkinliğimiz yok. Öte yandan optimizasyon yapmamıza ve yalnızca bir öğenin görünürlüğünü değiştirebilecek DOM değişikliklerinde yeniden kontrol yapmamıza olanak tanır.
Asla Hiç jQuery $ (document) .ready () içinde kullanmayın , çünkü şu anda hiçbir CSS uygulanmış garanti yoktur . Kodunuz sabit diskteki CSS'nizle yerel olarak çalışabilir, ancak uzak sunucuya yerleştirildikten sonra başarısız olur.
DOMContentLoaded
İşten çıkarıldıktan sonra stiller uygulanır , ancak görüntüler henüz yüklenmez . Bu yüzden window.onload
olay dinleyicisi eklemeliyiz .
Henüz zoom / pinch olayını yakalayamadık.
Son çare aşağıdaki kod olabilir:
/* TODO: this looks like a very bad code */
setInterval(handler, 600);
Web sayfanızdaki sekmenin etkin ve görünür olup olmadığını düşünüyorsanız, HTML5 API'sının harika özellik sayfasını kullanabilirsiniz .
YAPILACAKLAR: Bu yöntem iki durumu ele almaz:
z-index
overflow-scroll
elemanın kaptareturn (rect.bottom >= 0 && rect.right >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth));
isElementInViewport(document.getElementById('elem'))
, jQuery nesnesini (ör isElementInViewport($("#elem))
.) Değil , HTML DOM nesnesini (ör. ) Geçirmesi kolay bir hatırlatmadır . JQuery eşdeğer eklemektir [0]
şöyle: isElementInViewport($("#elem)[0])
.
el is not defined
Modern tarayıcılarda, aşağıdaki avantajları sağlayan Kesişim Gözlemcisi API'sına göz atmak isteyebilirsiniz :
Kavşak Gözlemcisi tam teşekküllü bir standart olma yolunda ilerliyor ve Chrome 51+, Edge 15+ ve Firefox 55+ sürümlerinde zaten destekleniyor ve Safari için geliştirilme aşamasında. Ayrıca bir çoklu dolgu da mevcuttur.
Dan'ın verdiği cevapta bazı durumlar için uygun olmayan bir yaklaşım olabilecek bazı sorunlar var . Bu sorunlardan bazıları, dibine yakın olan cevabında, kodunun aşağıdaki öğeler için yanlış pozitifler vereceğine dikkat çekiyor:
clip
özelliği kullanılarak gizlenen bir öğe veya alt öğeleriBu sınırlamalar basit bir testin aşağıdaki sonuçlarında gösterilmiştir :
isElementVisible()
Aşağıda, aşağıdaki test sonucu ve kodun bazı bölümlerinin açıklaması ile bu sorunlara bir çözüm.
function isElementVisible(el) {
var rect = el.getBoundingClientRect(),
vWidth = window.innerWidth || document.documentElement.clientWidth,
vHeight = window.innerHeight || document.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))
);
}
Başarılı sınav: http://jsfiddle.net/AndyE/cAY8c/
Ve sonuç:
Ancak bu yöntemin kendi sınırlamaları yoktur. Örneğin, aynı konumdaki başka bir öğeden daha düşük bir z-endeksiyle test edilen bir öğe, öndeki öğe aslında herhangi bir bölümünü gizlemese bile gizli olarak tanımlanır. Yine de, bu yöntemin Dan'ın çözümünün kapsamadığı bazı durumlarda kullanımları vardır.
Her ikisi de element.getBoundingClientRect()
ve document.elementFromPoint()
CSSOM Çalışma Taslağı belirtiminin bir parçasıdır ve en az IE 6 ve sonraki sürümlerde ve çoğu masaüstü tarayıcısında uzun süre (mükemmel olmasa da) desteklenmektedir. Daha fazla bilgi için bkz . Bu işlevler için Quirksmode .
contains()
tarafından döndürülen document.elementFromPoint()
öğenin görünürlük için test ettiğimiz öğenin alt düğümü olup olmadığını görmek için kullanılır . Ayrıca, döndürülen öğe aynı öğeyse true değerini döndürür. Bu sadece çeki daha sağlam yapar. Tüm büyük tarayıcılarda desteklenir, Firefox 9.0 en son eklenenleridir. Daha eski Firefox desteği için bu yanıtın geçmişini kontrol edin.
Görünürlük için öğenin etrafında daha fazla nokta denemek istiyorsanız, yani, öğenin, örneğin% 50'den daha fazla kapsama alanı içermediğinden emin olmak için cevabın son kısmını ayarlamak çok fazla zaman almaz. Ancak,% 100 görünür olduğundan emin olmak için her pikseli kontrol etmenizin çok yavaş olacağını unutmayın.
doc
Takma ad olarak kullandığım kodumdan kopyaladım document
. Evet, bunu uç durumlar için iyi bir çözüm olarak düşünmeyi seviyorum.
element.contains(efp(rect.right - (rect.width / 2), rect.bottom - (rect.height / 2)))
Dan'ın cevabını denedim . Bununla birlikte , sınırları belirlemek için kullanılan cebir, elemanın hem görüntü alanı boyutu hem de görüntü alanının tamamen içinde olması ve true
kolayca yanlış negatiflere yol açması gerektiği anlamına gelir . Bir öğenin görünüm alanında olup olmadığını belirlemek istiyorsanız, ryanve'nin yanıtı yakındır, ancak test edilen öğe görünümün üzerine gelmelidir, bu yüzden şunu deneyin:
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() */;
}
Bir kamu hizmeti olarak:
Dan'ın doğru hesaplamalarla yanıtı (öğe, özellikle cep telefonu ekranlarında pencere olabilir) ve doğru jQuery testinin yanı sıra isElementPartiallyInViewport ekleyerek:
Bu arada, window.innerWidth ve document.documentElement.clientWidth arasındaki fark , window.innerWidth / Height öğesinin clientWidth / clientHeight öğesinin kaydırma çubuğunu içermemesidir.
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);
}
<!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>
isElementPartiallyInViewport
de çok faydalıdır. Güzel bir.
GetBoundingClientRect kullanan verge kaynağına bakın . Gibi:
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
);
}
Bu döndürür true
eğer herhangi bir elemanın parçası viewport içindedir.
Daha kısa ve daha hızlı versiyonum:
function isElementOutViewport(el){
var rect = el.getBoundingClientRect();
return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}
Ve gerektiği gibi bir jsFiddle: https://jsfiddle.net/on1g619L/1/
Mevcut işlevsellik jQuery merkezli bir sürümü olmadığını rahatsız edici buldum . Ben karşıdan karşıya geldiğinde Dan çözümü jQuery OO tarzında programa gibi millet için bir şeyler sağlama fırsatı casusluk. Güzel ve çabuk ve benim için bir cazibe gibi çalışıyor.
Bada bing bada patlaması
$.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
// Is 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();
});
kullanım
$(window).on('scroll',function(){
if( $('footer').inView() ) {
// Do cool stuff
}
});
Yeni Kavşak Gözlemcisi API'sı bu soruyu çok doğrudan ele alıyor.
Safari, Opera ve Internet Explorer henüz bunu desteklemediğinden bu çözümün bir çoklu dolguya ihtiyacı olacaktır (çoklu dolgu çözüme dahil edilmiştir).
Bu çözümde, hedef (gözlenen) olan bir kutu vardır. Görünmeye geldiğinde, başlığın üstündeki düğme gizlenir. Kutu görünümden ayrıldığında gösterilir.
const buttonToHide = document.querySelector('button');
const hideWhenBoxInView = new IntersectionObserver((entries) => {
if (entries[0].intersectionRatio <= 0) { // If not in view
buttonToHide.style.display = "inherit";
} else {
buttonToHide.style.display = "none";
}
});
hideWhenBoxInView.observe(document.getElementById('box'));
header {
position: fixed;
top: 0;
width: 100vw;
height: 30px;
background-color: lightgreen;
}
.wrapper {
position: relative;
margin-top: 600px;
}
#box {
position: relative;
left: 175px;
width: 150px;
height: 135px;
background-color: lightblue;
border: 2px solid;
}
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<header>
<button>NAVIGATION BUTTON TO HIDE</button>
</header>
<div class="wrapper">
<div id="box">
</div>
</div>
<!DOCTYPE html>
HTML
IntersectionObserver
deneysel bir özellik olduğunu unutmayın (gelecekte değişebilir).
IntersectionObserver
sadece hedefin köke göre hareketinden sonra geri arama yapar.
observe
olayı hemen izlendiğinde, izlenen öğenin geçerli kavşak durumunu gösterir. Yani, bir şekilde - hitap ediyor.
Burada karşılaştığım tüm yanıtlar yalnızca öğenin geçerli görünümün içine yerleştirilip yerleştirilmediğini kontrol eder . Ancak bu görünür olduğu anlamına gelmez .
Belirli bir öğe taşan içeriğe sahip bir div içindeyse ve görünümden dışarı kaydırılırsa ne olur?
Bunu çözmek için, öğenin tüm ebeveynler tarafından bulunup bulunmadığını kontrol etmeniz gerekir.
Benim çözüm tam olarak bunu yapar:
Ayrıca, öğenin ne kadarının görünür olması gerektiğini belirtmenize de olanak tanır.
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;
};
Bu çözüm, diğer gerçekler nedeniyle elementlerin görünmeyebileceği gerçeğini göz ardı etmiştir opacity: 0
.
Bu çözümü Chrome ve Internet Explorer 11'de test ettim.
Burada kabul edilen cevabın çoğu kullanım durumunda aşırı derecede karmaşık olduğunu görüyorum. Bu kod işi iyi yapar (jQuery kullanarak) ve tamamen görünür ve kısmen görünür öğeler arasında ayrım yapar:
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");
}
});
$window = $(window)
kaydırma işleyicisinin dışında önbellek kullanmalısınız .
En basit çözüm desteği olarak Element.getBoundingClientRect () olan mükemmel hale :
function isInView(el) {
let box = el.getBoundingClientRect();
return box.top < window.innerHeight && box.bottom >= 0;
}
Bunun daha işlevsel bir yolu olduğunu düşünüyorum. Dan'ın yanıtı özyinelemeli bir bağlamda çalışmaz.
Bu işlev, HTML etiketine kadar herhangi bir düzeyi yinelemeli olarak test ederek öğeniz diğer kaydırılabilir div'ların içinde olduğunda sorunu çözer ve ilk yanlışta durur.
/**
* 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)
);
};
En çok kabul edilen yanıtlar Android'de Google Chrome'u yakınlaştırırken çalışmaz. Dan'ın cevabı ile birlikte , Android'de Chrome'u hesaba katmak için visualViewport kullanılmalıdır. Aşağıdaki örnek yalnızca dikey denetimi dikkate alır ve pencere yüksekliği için jQuery kullanır:
var Rect = YOUR_ELEMENT.getBoundingClientRect();
var ElTop = Rect.top, ElBottom = Rect.bottom;
var WindowHeight = $(window).height();
if(window.visualViewport) {
ElTop -= window.visualViewport.offsetTop;
ElBottom -= window.visualViewport.offsetTop;
WindowHeight = window.visualViewport.height;
}
var WithinScreen = (ElTop >= 0 && ElBottom <= WindowHeight);
İşte benim çözümüm. Kaydırılabilir bir kabın içinde bir öğe gizlenmişse çalışır.
İşte bir demo (pencereyi yeniden boyutlandırmayı deneyin)
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 it's within the document viewport
return top <= document.documentElement.clientHeight;
};
Sadece Y ekseninde görünüp görünmediğini kontrol etmem gerekiyordu (kaydırma Ajax daha fazla yük kaydı özelliği için).
Dan'ın çözümüne dayanarak , uygulamayı aynı sayfada birden çok kez kullanmak daha kolay olacak şekilde temizlemeye gitmiştim:
$(function() {
$(window).on('load resize scroll', function() {
addClassToElementInViewport($('.bug-icon'), 'animate-bug-icon');
addClassToElementInViewport($('.another-thing'), 'animate-thing');
// 👏 repeat as needed ...
});
function addClassToElementInViewport(element, newClass) {
if (inViewport(element)) {
element.addClass(newClass);
}
}
function inViewport(element) {
if (typeof jQuery === "function" && element instanceof jQuery) {
element = element[0];
}
var elementBounds = element.getBoundingClientRect();
return (
elementBounds.top >= 0 &&
elementBounds.left >= 0 &&
elementBounds.bottom <= $(window).height() &&
elementBounds.right <= $(window).width()
);
}
});
Bunu kullanıyorum, öğe görünüme kaydırıldığında, bir CSS ana kare animasyonunu tetikleyen bir sınıf ekliyorum. Oldukça basittir ve bir sayfada koşullu olarak animasyon uygulamak için 10'dan fazla şey olduğunda özellikle iyi çalışır.
$window = $(window)
kaydırma işleyicisinin önbelleğini almalısınız
Önceki yanıtlardaki kullanımların çoğu şu noktalarda başarısız oluyor:
-Bir öğenin herhangi bir pikseli görünürken, " köşe " " olmadığında,
-Bir öğe görünüm penceresinden daha büyük ve ortalandığında ,
-Çoğu sadece bir belge veya pencere içinde tekil bir öğe olup olmadığını kontrol ediyor .
Tüm bu problemler için bir çözümüm var ve artı taraflar:
-Geri dönebilirsiniz
visible
bir taraftan bir piksel göründüğünde ve bir köşe olmadığında ,- Hala dönebilirsin
visible
öğe görüntü alanından daha büyükken ,-Seçebilirsiniz
parent element
veya otomatik olarak seçmesine izin verebilirsiniz,-Dinamik olarak eklenen öğeler üzerinde de çalışır.
Kullandığınız farkı göreceksiniz Aşağıdaki parçacıkları işaretlerseniz overflow-scroll
herhangi bir sorun neden olmaz öğenin kapta ve görüyoruz burada aksine diğer cevaplar bile piksel gösterileri yukarıya doğru eğer herhangi tarafında veya bir eleman görüntü alanından daha büyüktür ve biz görüyoruz iç hala çalıştığı öğenin pikselleri .
Kullanımı basit:
// For checking element visibility from any sides
isVisible(element)
// For checking elements visibility in a parent you would like to check
var parent = document; // Assuming you check if 'element' inside 'document'
isVisible(element, parent)
// For checking elements visibility even if it's bigger than viewport
isVisible(element, null, true) // Without parent choice
isVisible(element, parent, true) // With parent choice
crossSearchAlgorithm
Görüntü alanı kontrol elemanından3 büyük pikselden daha büyük elemanlar için kullanışsız bir tanıtım :
Görüyorsunuz , element3'ün içindeyken görünür olup olmadığını söyleyemiyor, çünkü sadece öğenin kenarlardan veya köşelerden görünür olup olmadığını kontrol ediyoruz .
Ve bu , öğe görünüm penceresinden daha büyük olduğunda crossSearchAlgorithm
hala geri dönmenizi sağlayan şunları içerir visible
:
JSFiddle ile oynamak için: http://jsfiddle.net/BerkerYuceer/grk5az2c/
Bu kod, öğenin herhangi bir kısmı görünümde gösteriliyorsa veya gösterilmiyorsa daha kesin bilgi için yapılır. Performans seçenekleri veya yalnızca dikey slaytlar için bunu kullanmayın! Bu kod çizim durumlarında daha etkilidir.
Daha iyi bir çözüm:
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;
}
Bir öğenin, üst öğenin geçerli görünüm penceresinde görünür olup olmadığını bildiren bir işlev şunlardır :
function inParentViewport(el, pa) {
if (typeof jQuery === "function"){
if (el instanceof jQuery)
el = el[0];
if (pa instanceof jQuery)
pa = pa[0];
}
var e = el.getBoundingClientRect();
var p = pa.getBoundingClientRect();
return (
e.bottom >= p.top &&
e.right >= p.left &&
e.top <= p.bottom &&
e.left <= p.right
);
}
Bu, bir öğenin en azından kısmen görünümde olup olmadığını kontrol eder (dikey boyut):
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}
}
Aynı soru vardı ve getBoundingClientRect () kullanarak anladım.
Bu kod tamamen 'jenerik' ve çalışması için sadece bir kez yazılması gerekiyor (bilmek istediğiniz her öğe için görünümde yazmak zorunda değilsiniz).
Bu kod yalnızca dikey olarak görünüm alanında olup olmadığını kontrol eder, yatay değil . Bu durumda, değişken (dizi) 'öğeleri' görünüm alanında dikey olarak olmasını kontrol ettiğiniz tüm öğeleri tutar, bu nedenle istediğiniz herhangi bir öğeyi istediğiniz yere alın ve orada saklayın.
'For döngüsü', her öğede dolaşır ve görünüm alanında dikey olup olmadığını kontrol eder. Bu kod , kullanıcı her kaydırdığında yürütülür! GetBoudingClientRect (). Top, görünüm penceresinin 3 / 4'ünden küçükse (öğe görünüm penceresinde dörtte birdir), 'görünüm penceresinde' olarak kaydedilir.
Kod genel olduğundan, görünüm penceresinde 'hangi' öğenin olduğunu bilmek isteyeceksiniz. Bunu bulmak için, özel özellik, düğüm adı, kimlik, sınıf adı ve daha fazlasına göre belirleyebilirsiniz.
İşte kodum (çalışmadığını söyle; Internet Explorer 11, Firefox 40.0.3, Chrome Sürüm 45.0.2454.85 m, Opera 31.0.1889.174 ve Edge ile Windows 10'da test edildi, henüz Safari'de değil ]) ...
// 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.');
}
};
Bu benim için çalışan kolay ve küçük bir çözüm.
Örnek : Öğenin taşma kaydırması olan üst öğede görünür olup olmadığını görmek istiyorsunuz.
$(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');
}
})
Buradaki tüm cevaplar, öğenin yalnızca bir şekilde görünür değil, görünüm alanında tamamen bulunup bulunmadığını belirler. Örneğin, bir görüntünün yalnızca yarısı görünümün altında görünürse, buradaki çözümler "dışarıda" dikkate alındığında başarısız olur.
Ben aracılığıyla tembel yükleme yapıyorum bir kullanım durumunda vardı IntersectionObserver
, fakat ben olan tüm görüntüleri gözlemlemek istemiyordu-pop sırasında meydana animasyonlara zaten sayfa yüklemesinde kesişen. Bunu yapmak için aşağıdaki kodu kullandım:
const bounding = el.getBoundingClientRect();
const isVisible = (0 < bounding.top && bounding.top < (window.innerHeight || document.documentElement.clientHeight)) ||
(0 < bounding.bottom && bounding.bottom < (window.innerHeight || document.documentElement.clientHeight));
Bu temel olarak üst veya alt sınırın bağımsız olarak görünüm alanında olup olmadığını kontrol eder. Karşı uç dışarıda olabilir, ancak bir uç olduğu sürece, en azından kısmen "görülebilir".
Bu işlevi kullanıyorum (çoğu zaman x gerekli olmadığından yalnızca y'nin ekran olup olmadığını kontrol eder)
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;
}
}
Benzer bir meydan okuma için, scrollIntoViewIfNeeded () için bir çoklu dolgu gösteren bu özü gerçekten keyif aldım .
Cevaplamak için gereken tüm Kung Fu bu blokta:
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
örneğin, olup olmadığını bilmek istediğiniz öğeye atıfta bulunur, overTop
ya da overBottom
- sadece sapmayı almalısınız ...