滚动父div后,如何检测哪个子元素可见?

时间:2019-07-12 03:23:29

标签: javascript html css scroll

我想使用div(例如PDF阅读器)模拟类似“当前页面”的内容

document.addEventListener("DOMContentLoaded", function(event) {
  var container = document.getElementById("container");
  container.onscroll = function() {
    let position = container.scrollTop;
    let divs = document.querySelectorAll('.page');
    for (div of divs) {
      //???
    }
  }
});
#container {
  width: 400px;
  height: 600px;
  overflow: auto;
}

.page {
  width: 400px;
}

.red {
  background-color: red;
  height: 600px;
}

.blue {
  background-color: blue;
  height: 400px;
}
Current page: <span id="page-counter">1</span>
<div id='container'>
  <div id="div-1" class="page red"></div>
  <div id="div-2" class="page blue"></div>
  <div id="div-3" class="page red"></div>
  <div id="div-4" class="page blue"></div>
</div>

因此,我想知道最好的方法,例如,当第三个div“出现”时,将跨页计数器文本更改为“ 3”

类似这样的内容:https://i.imgur.com/rXQ2Bw8.png

预先感谢 塞尔索(Celso)

3 个答案:

答案 0 :(得分:2)

由于此问题从未标记过jQuery,因此这是一个纯Javascript解决方案,它以我所知尽可能地模拟了您正在寻找的行为。该解决方案计算容器内当前可见的每个子元素的像素数量。如果数量大于或等于容器大小的一半,则假定这是您的访客正在查看的页面。

function getVisibleHeight(element){
	const container = document.getElementById("container");
	let scrollTop = container.scrollTop;
	let scrollBot = scrollTop + container.clientHeight;
	let containerRect = container.getBoundingClientRect();
	let eleRect = element.getBoundingClientRect();
	let rect = {};
	rect.top = eleRect.top - containerRect.top,
	rect.right = eleRect.right - containerRect.right,
	rect.bottom = eleRect.bottom - containerRect.bottom,
	rect.left = eleRect.left - containerRect.left;
	let eleTop = rect.top + scrollTop;
	let eleBot = eleTop + element.offsetHeight;
	let visibleTop = eleTop < scrollTop ? scrollTop : eleTop;
	let visibleBot = eleBot > scrollBot ? scrollBot : eleBot;

	return visibleBot - visibleTop;
}

document.addEventListener("DOMContentLoaded", function(event) {
	const container = document.getElementById("container");
	const divs = document.querySelectorAll('.page');

	container.addEventListener("scroll", () => {
		for(let i=0; i<divs.length; i++){
			const containerHeight = container.clientHeight;

			// Gets the amount of pixels currently visible within the container
			let visiblePageHeight = getVisibleHeight(divs[i]);

			// If the amount of visible pixels is bigger or equal to half the container size, set page
			if(visiblePageHeight >= containerHeight / 2){
				document.getElementById('page-counter').innerText = i+1;
			}
		}
	}, false);
});
#container {
	width: 400px;
	height: 300px;
	overflow: auto;
}

.page {
	width: 380px;
}

.red {
	background-color: red;
	height: 300px;
}

.blue {
	background-color: blue;
	height: 200px;
}
Current page: <span id="page-counter">1</span>
<div id='container'>
	<div id="div-1" class="page red"></div>
	<div id="div-2" class="page blue"></div>
	<div id="div-3" class="page red"></div>
	<div id="div-4" class="page blue"></div>
</div>

答案 1 :(得分:0)

您可以使用jQuery中的visible功能。只需为每个div分配一个唯一的ID或类即可。

if( $("#uniqueIdHere").is(':visible'))
   $(".page3Selector").addClass('active');

,然后要删除活动类,可以将其与else语句配对以删除不活动div的类。

答案 2 :(得分:0)

这里的一般方法是编写一个确定给定HTML元素是否在视口中的函数。您可以在用户滚动时运行检查。有关jQuery的示例,请参见下面的代码片段。我并不一定要说这是最好的方法,但这似乎是可行的。开始滚动以查看ID出现。

function isInViewPort(element) {
  // Function will determine if any part of the element is in the viewport.
  let $el = $("#" + element);
  let windowScrollTop = $(window).scrollTop();
  let windowHeight = $(window).height();
  let windowBottom = windowScrollTop + windowHeight;
  let elementTop = $el.offset().top;
  let elementOuterHeight = $el.outerHeight();
  let elementBottom = elementTop + elementOuterHeight;

  let isAboveViewPort = elementBottom < windowScrollTop;
  let isBelowViewPort = windowBottom < elementTop;

  return !(isAboveViewPort || isBelowViewPort);
}

let currentDiv;

$("#container").on("scroll", function() {
  $("#container").find("div").each(function() {
    if (isInViewPort(this.id) && currentDiv !== this.id) {
      $("#page").html("Current ID is " + this.id)
      currentDiv = this.id;
    }
  });
});
#container {
  overflow: auto;
  height: 300px;
}

.red {
  background-color: red;
  height: 600px;
}

.blue {
  background-color: blue;
  height: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="page"></span>
<div id='container'>
  <div id="div-1" class="page red"></div>
  <div id="div-2" class="page blue"></div>
  <div id="div-3" class="page red"></div>
  <div id="div-4" class="page blue"></div>
</div>