获取占据父元素顶部的元素

时间:2016-02-16 05:27:35

标签: javascript html

如果父div可以垂直滚动并且可能嵌套了元素,那么如何获得当前占据父div顶端的(最里面的)元素?

例如,假设我将父div作为下图中的浅蓝色区域,并且其中有对象,其中有蓝色或红色,其中一些部分位于父div之外(实际应该是隐藏)。我想让对象用红色着色。

nesting

我可以通过将子元素的offsetTop与父元素的coo_matrix进行比较来实现,并递归进入。

2 个答案:

答案 0 :(得分:2)

运行下面的代码段以查看一个解决方案。滚动窗口以相对于窗口移动div,然后单击按钮以查看窗口顶部最里面的div的id。该解决方案假设所有div都是“通常”嵌套的,即没有通过花式css工作重新排列div垂直放置,没有固定位置等。

下面有两个版本:第一个使用jQuery,第二个不使用。

$("button#check").click(function() {
  var topElem = $("body")[0];                          // start at the outermost, i.e. the body
  var checkChildDivs = function() {                    // define the recursive checking function
    var children = $(topElem).children("div").not("div#info"); // get all child divs
    if (children.length > 0) {                         // if there are any child divs
      $(children).each(function(index, elem) {         // check each of them
        var posns = getPosns($(elem));                 // get their top and bottom posns
                                                       //   relative to the top of the screen
        if ((posns.top <= 0) && (posns.bottom >= 0)) { // if the div overlaps the screen top
          topElem = elem;                              // make this the new innermost div
          checkChildDivs();                            // check any deeper child divs
          return false;                                // no need to check any lower sibling divs
        }
      });
    }
  };
  checkChildDivs();                                    // initiate the checking recursion
  $("div#info").text($(topElem).attr("id") || "none, i.e. body"); // report the innermost top div id
});

function getPosns($elem) {
  var top = $elem.offset().top;    // get the top of the div relative to the document
  var hgt = $elem.outerHeight();   // get the height of the element
  var wst = $(window).scrollTop(); // get the height of window hidden above the top of the screen
  return {                         // return the top and bottom distances of the element
    top: (top - wst),              // relative to the top of the screen
    bottom: (top - wst + hgt)
  };
}
body {
  background-color: blue;
}
div {
  border: solid black 2px;
  padding: 1em;
  margin: 1em;
  background-color: magenta;
}
div > div {
  background-color: red;
}
div > div > div {
  background-color: orange;
}
div >div > div > div {
  background-color: yellow;
}
button#check {
  position: fixed;
  height: 2em;
}
div#info {
  position: fixed;
  background-color: white;
  border-width: 1px;
  opacity: 0.7;
  top: 3em;
  left: -0.2em;
  height: 1.5em;
  width: 15em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="check">Determine Id of Innermost Div at Screen Top</button>
<div id="info"></div>
<div id="a">a
  <div id="aa">aa
    <div id="aaa">aaa</div>
    <div id="aab">aab
      <div id="aaba">aaba</div>
      <div id="aabb">aabb</div>
      <div id="aabc">aabc</div>
    </div>
    <div id="aac">aac</div>
  </div>
  <div id="ab">ab
    <div id="aba">aba</div>
    <div id="abb">abb</div>
    <div id="abc">abc</div>
  </div>
  <div id="ac">ac
    <div id="aca">aca</div>
    <div id="acb">acb</div>
    <div id="acc">acc</div>
  </div>
</div>
<div id="b">b
  <div id="ba">ba
    <div id="baa">baa</div>
    <div id="bab">bab</div>
    <div id="bac">bac</div>
  </div>
  <div id="bb">bb
    <div id="bba">bba</div>
    <div id="bbb">bbb</div>
    <div id="bbc">bbc</div>
  </div>
  <div id="bc">bc
    <div id="bca">bca</div>
    <div id="bcb">bcb</div>
    <div id="bcc">bcc</div>
  </div>
</div>
<div id="c">c
  <div id="ca">ca
    <div id="caa">caa</div>
    <div id="cab">cab</div>
    <div id="cac">cac</div>
  </div>
  <div id="cb">cb
    <div id="cba">cba</div>
    <div id="cbb">cbb</div>
    <div id="cbc">cbc</div>
  </div>
  <div id="cc">cc
    <div id="cca">cca</div>
    <div id="ccb">ccb</div>
    <div id="ccc">ccc</div>
  </div>
</div>

这是同一件事的非jQuery版本:

var doc = document;
doc.getElementById("check").onclick = function() {
  var topElem = doc.getElementsByTagName("body")[0];     // start at the outermost, i.e. the body
  var checkChildDivs = function() {                      // define the recursive checking function
    var children = topElem.childNodes;                   // get all child nodes
    if (children.length > 0) {                           // if there are any child nodes
      [].forEach.call(children, function(elem, index, arr) { // check each of them
        if (elem.toString() === "[object HTMLDivElement]" && elem.id !== "info") {
                                                         // only use divs that do not have id "info"
          var posns = getPosns(elem);                    // get their top and bottom posns
                                                         //   relative to the top of the screen
          if ((posns.top <= 0) && (posns.bottom >= 0)) { // if the div overlaps the screen top
            topElem = elem;                              // make this the new innermost div
            checkChildDivs();                            // check any deeper child divs
            return false;                                // no need to check any lower sibling divs
          }
        }
      });
    }
  };
  checkChildDivs();                                      // initiate the checking recursion
  doc.getElementById("info").innerHTML = (topElem.id || "none, i.e. body");
                                                         // report the innermost top div id
};

function getPosns(elem) {
  var top = elem.getBoundingClientRect().top + window.pageYOffset - doc.documentElement.clientTop;
                                   // get the top of the div relative to the document
  var hgt = elem.offsetHeight;     // get the height of the element
  var wst = window.scrollY;        // get the height of window hidden above the top of the screen
  return {                         // return the top and bottom distances of the element
    top: (top - wst),              // relative to the top of the screen
    bottom: (top - wst + hgt)
  };
}
body {
  background-color: blue;
}
div {
  border: solid black 2px;
  padding: 1em;
  margin: 1em;
  background-color: magenta;
}
div > div {
  background-color: red;
}
div > div > div {
  background-color: orange;
}
div >div > div > div {
  background-color: yellow;
}
button#check {
  position: fixed;
  height: 2em;
}
div#info {
  position: fixed;
  background-color: white;
  border-width: 1px;
  opacity: 0.7;
  top: 3em;
  left: -0.2em;
  height: 1.5em;
  width: 15em;
}
<button id="check">Determine Id of Innermost Div at Screen Top</button>
<div id="info"></div>
<div id="a">a
  <div id="aa">aa
    <div id="aaa">aaa</div>
    <div id="aab">aab
      <div id="aaba">aaba</div>
      <div id="aabb">aabb</div>
      <div id="aabc">aabc</div>
    </div>
    <div id="aac">aac</div>
  </div>
  <div id="ab">ab
    <div id="aba">aba</div>
    <div id="abb">abb</div>
    <div id="abc">abc</div>
  </div>
  <div id="ac">ac
    <div id="aca">aca</div>
    <div id="acb">acb</div>
    <div id="acc">acc</div>
  </div>
</div>
<div id="b">b
  <div id="ba">ba
    <div id="baa">baa</div>
    <div id="bab">bab</div>
    <div id="bac">bac</div>
  </div>
  <div id="bb">bb
    <div id="bba">bba</div>
    <div id="bbb">bbb</div>
    <div id="bbc">bbc</div>
  </div>
  <div id="bc">bc
    <div id="bca">bca</div>
    <div id="bcb">bcb</div>
    <div id="bcc">bcc</div>
  </div>
</div>
<div id="c">c
  <div id="ca">ca
    <div id="caa">caa</div>
    <div id="cab">cab</div>
    <div id="cac">cac</div>
  </div>
  <div id="cb">cb
    <div id="cba">cba</div>
    <div id="cbb">cbb</div>
    <div id="cbc">cbc</div>
  </div>
  <div id="cc">cc
    <div id="cca">cca</div>
    <div id="ccb">ccb</div>
    <div id="ccc">ccc</div>
  </div>
</div>

答案 1 :(得分:1)

您可以使用此库:https://github.com/customd/jquery-visible。 查看我的代码片段以获取演示

$(function() {
  $(window).on('scroll', function() {
    $visible = null;
    $('section > div').each(function() {
      if (!$visible && $(this).visible(true)) {
        $visible = $(this);
        $(this).addClass('active');
      } else {
        $(this).removeClass('active');
      }
    });
    $('#answer').html('' + $visible.text());
  });
});
#main1,
#main2,
#main3,
#main4 {
  display: block;
  padding: 10px;
}
body {
  background: blue;
}
section > div {
  display: block;
  width: 100%;
  background: lightblue;
  margin-bottom: 10px;
}
section > div.active {
  background: red;
}
#answer {
  display: block;
  position: fixed;
  bottom: 0;
  height: 30px;
  width: 300px;
  background: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://opensource.teamdf.com/visible/jquery.visible.js"></script>
<section id="main1">
  <div style="height:100px;">child 1</div>
</section>
<section id="main2">
  <div style="height:100px;">child 2</div>
</section>
<section id="main3">
  <div style="height:100px;">child 3</div>
</section>
<section id="main4">
  <div style="height:300px;">child 4</div>
  <div style="height:400px;">child 5</div>
</section>
<div id="answer"></div>