如何检测具有父`overflow:hidden;`的元素是否被隐藏?

时间:2017-06-11 05:29:36

标签: javascript jquery html css

假设我有以下HTML

<div id="someContainer" style="overflow:hidden; height:300px">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  ....(countless of similar items)
</div>

如何使用JQuery或JS检测此案例中隐藏的第一个项目? stackOverflow上给出的大量解决方案不适用于具有overflow:hidden

的父元素的情况

3 个答案:

答案 0 :(得分:1)

编辑:我的强制迫使我在没有jQuery的情况下更改此代码并更正错误

这是一个jsFiddle快速测试,我重复下面的代码:

HTML:

<div id="someContainer" style="overflow:hidden; position:relative; height:26px; background-color: #ffffff;">
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>
<pre id="output"></pre>

JS(没有jQuery):

var i, top, container, output, height;

container = document.getElementById("someContainer");
output = document.getElementById("output");
height = container.offsetHeight;

output.innerText += "Height: " + height + "px\n";

for (i = 0; i < container.children.length; i++)
{
  top = container.children[i].offsetTop;
  output.innerText += "Top " + i + ": " + top + "px => visible=" + (top < height) + "\n";
}

输出将是:

Height: 26px
Top 0: 0px => visible=true
Top 1: 18px => visible=true
Top 2: 36px => visible=false

前两项是可见的(至少在某种程度上,我故意将B切成两半),而最后一项则不可见。它超出了容器的下边缘。

  

注意:我必须将position: relative;添加到容器中,以便它成为子元素的定位参考。否则,offsetTop会在特定情况下计算错误(取决于外部HTML)。

答案 1 :(得分:0)

这是一个简单的方法,它将遍历容器的子节点,并在符合条件的第一个节点停止

el.offsetTop > parent.offsetHeight + parent.scrollTop;

&#13;
&#13;
function find_firstHidden(container, full) {
  var items = container.querySelectorAll('*'); // get all nodes
  var maxTop = container.scrollTop + container.offsetHeight; // get the container's maxTop
  var found;
  for (var i = 0; i < items.length; i++) {
    // if we want to get the first element truncated, add its offsetHeight in the condition
    var o_top = full ? items[i].offsetTop + items[i].offsetHeight : items[i].offsetTop;
    if (o_top > maxTop) {
      found = items[i];
      return found;
    }
  }
  return null;
}
// set the element before the first completely hidden node red
find_firstHidden(someContainer)
  .previousElementSibling.style.background = 'red';
// set the element before the first partially hidden node green
find_firstHidden(someContainer, true)
  .previousElementSibling.style.background = 'green';
&#13;
.item {
  height: 50px;
  border: 1px solid;
}
&#13;
<div id="someContainer" style="overflow:hidden; height:300px">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>
&#13;
&#13;
&#13;

请注意,如果您要处理大量节点,那么TreeWalker可能会提供更好的性能(将应用相同的条件)

答案 2 :(得分:0)

以防万一有人正在寻找一个稍微灵活的答案来查找元素是否被具有溢出的父元素隐藏,这将查看元素的所有父元素并检查它是否被隐藏或部分隐藏所有这些。它返回一个小数,其中 1 是完全可见的,0 是完全隐藏的,以及介于两者之间的任何位置。我发现测试下拉列表是否部分隐藏并且应该弹出而不是向下很有用。

它在大多数情况下使用 JQuery,但下划线也很有帮助。这根本没有优化,所以...

function recursivePartialIsVisible(element: HTMLElement): number {
    const elementBoundary = {
        top: $(element).offset().top,
        left: $(element).offset().left,
        bottom: $(element).offset().top + $(element).height(),
        right: $(element).offset().left + $(element).width(),
        height: $(element).height(),
        width: $(element).width()
    };


    const visibility = _.chain($(element).parents())
        .map(parent => $(parent))
        .filter(parent => 
            parent.css('overflow') === 'hidden' || 
            parent.css('overflow') === 'scroll' || 
            parent.css('overflow') === 'auto' || 
            parent.css('overflow-y') === 'hidden' || 
            parent.css('overflow-y') === 'scroll' || 
            parent.css('overflow-y') === 'auto'
        )
        .map(parent => {
            const parentBoundary = {
                top: parent.offset().top,
                left: parent.offset().left,
                bottom: parent.offset().top + parent.innerHeight(),
                right: parent.offset().left + parent.innerWidth(),
                height: parent.innerHeight(),
                width: parent.innerWidth()
            };
            if(
                elementBoundary.bottom < parentBoundary.top || 
                elementBoundary.top > parentBoundary.bottom ||
                elementBoundary.left > parentBoundary.right ||
                elementBoundary.right < parentBoundary.left) {
                    return 0;
                }
            
            const areaOverlap = 
                (Math.max(elementBoundary.left, parentBoundary.left) - Math.min(elementBoundary.right, parentBoundary.right)) 
                * 
                (Math.max(elementBoundary.top, parentBoundary.top) - Math.min(elementBoundary.bottom, parentBoundary.bottom));

            const percentageOverlap = areaOverlap / (elementBoundary.height * elementBoundary.width);

            return percentageOverlap;
        })
        .reduce((previous, current) => previous * current, 1)
        .value();

    
    return visibility;
}

注意:数学是从here借来的