是否有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(出现在视口中)?

(这个问题指的是Firefox。)


当前回答

我们现在有一个原生javascript交集观察者API 从中我们可以检测元素,无论它们是否在视口中。

这里有一个例子

const el = document.querySelector('#el') const observer = new window.IntersectionObserver(([entry]) => { if (entry. isintersection) { console.log(输入) 返回 } console.log(离开) }, { 根:空, 阈值:0.1,//设置偏移量0.1表示如果元素在视口中至少占10%,则触发 }) observer.observe (el); 身体{ 身高:300 vh; } # el { margin-top: 100 vh; } <div id="el">这是元素</div>

其他回答

更新:时间在流逝,我们的浏览器也是如此。这种方法不再被推荐,如果你不需要支持ie7之前的版本,你应该使用Dan的解决方案。

原来的解决方案(现已过时):

这将检查元素是否在当前视口中完全可见:

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

你可以简单地修改它,以确定元素的任何部分在视口中是否可见:

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

下面是检查给定元素在其父元素中是否完全可见的代码片段:

export const visibleInParentViewport = (el) => {
  const elementRect = el.getBoundingClientRect();
  const parentRect = el.parentNode.getBoundingClientRect();

  return (
    elementRect.top >= parentRect.top &&
    elementRect.right >= parentRect.left &&
    elementRect.top + elementRect.height <= parentRect.bottom &&
    elementRect.left + elementRect.width <= parentRect.right
  );
}

下面是一个函数,它告诉你一个元素在父元素的当前视口中是否可见:

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

我有同样的问题,并通过使用getBoundingClientRect()来解决。

这段代码完全是“通用的”,只需要写一次就可以工作(你不需要为你想知道的每个元素都写出来)。

这段代码只检查它在视口中是否垂直,而不是水平。在本例中,变量(array)'elements'保存了所有你要检查的垂直在视口中的元素,所以在任何地方抓取任何你想要的元素并将它们存储在那里。

for循环遍历每个元素并检查它是否垂直地位于视口中。这段代码在用户每次滚动时执行!如果getBoudingClientRect()。Top小于viewport的3/4(元素在viewport中的四分之一),它注册为“在viewport中”。

因为代码是通用的,你会想知道“哪个”元素在视口中。要找出这一点,可以通过自定义属性、节点名、id、类名等确定。

这是我的代码(如果它不起作用,请告诉我;它已在Internet Explorer 11、Firefox 40.0.3、Chrome Version 45.0.2454.85 m、Opera 31.0.1889.174和Edge with 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.');
   }
};

对于类似的挑战,我非常喜欢这个要点,它为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;

这指的是你想知道的元素,例如,overTop或overBottom -你只需要得到漂移…