计算已滚动到视图中的特定元素的百分比

时间:2017-10-20 14:16:45

标签: javascript jquery

假设您有一个包含多个大面板的网页,您可以使用以下代码轻松计算用户滚动到的整个页面的百分比。

$(window).scroll(function(){

    var windowTop = $(this).scrollTop()
    var bodyHeight = $('body').height()

    var percentage = (windowTop/bodyHeight) * 100
    console.log(percentage)

});

然而,我想要做的是计算,对于一个单独的面板,该面板的百分比已滚动到视口中。因此,在你进入面板之前,这将是0%,并且一旦你滚动到该面板的底部,它将是100%。

我觉得这可能是一个简单的等式,但我无法将我的大脑包裹在我需要做的事情之中。

3 个答案:

答案 0 :(得分:4)

这是一个构造函数,它可以监视给定元素并返回有关屏幕上百分比的数据对象。它会监视视口上方和下方的元素。



var OnScreenPercentage = function(querySelector, callback){
  var self = this;
  this.callback = callback;
  this.elements = querySelector?$(querySelector):[];

  this.remove = function(){
    if(this.handler){
      $(window).off("scroll", this.handler);
    }
  }
  var calcTop = function(rect, win){
    return Math.max(rect.height+rect.y, 0)/rect.height;
  }
  var calcBottom = function(rect, win){
    return Math.max(win.height-rect.y, 0)/rect.height;
  }
  var calcPercentages = function(){
      var win = {height: $(window).height()}; 
      for(var e=0; e<self.elements.length; ++e){
        var rect = self.elements[e].getBoundingClientRect();
        self.callback({
          element: self.elements[e],
          percentage: rect.y<0 ? calcTop(rect, win) : (rect.y+rect.height)>win.height ? calcBottom(rect, win) : 1,
          location: rect.y<0 ? 'top' : (rect.y+rect.height)>win.height ? 'bottom' : 'middle'
        });
      }
  }
  this.handler = $(window).scroll(calcPercentages);
  calcPercentages();
}

//Example usage
var onScreen = new OnScreenPercentage('.box', function(data){
  var percent =  $(data.element).find('.percentage');
  $(percent).width(100*data.percentage+'%');
  if(data.location=='top'||data.location=='middle'){
    $(percent).css({left:'0', right: ''});
  }else{
    $(percent).css({left:'', right:'0'});
  }
});
&#13;
.box {
  height: 100px;
  line-height: 100px;
  background-color: rgba(0,0,0,0.1);
  margin: 5px;
  position: relative;
  color: #fff;
  font-size: 30px;
  text-align: center;
}
.percentage {
  background: #00F;
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: -1;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="box">Box 0 <div class="percentage"></div></div>
<div class="box">Box 1 <div class="percentage"></div></div>
<div class="box">Box 2 <div class="percentage"></div></div>
<div class="box">Box 3 <div class="percentage"></div></div>
<div class="box">Box 4 <div class="percentage"></div></div>
<div class="box">Box 5 <div class="percentage"></div></div>
<div class="box">Box 6 <div class="percentage"></div></div>
<div class="box">Box 7 <div class="percentage"></div></div>
<div class="box">Box 8 <div class="percentage"></div></div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

如果我理解正确,从您的描述中可以看出您希望看到元素何时进入视口。

这意味着您需要计算窗口底部的位置(以便您可以将其与元素顶部的位置进行比较)。您可以像这样计算窗口底部的位置:

var windowBottom = $(this).scrollTop() + $(this).height();

然后你需要知道元素进入视口的位置。您可以像这样获得元素的顶部位置:

var elementTop = $(".element").offset().top;

然后,您可以通过从窗口底部的位置减去元素的顶部位置来计算已滚动到视口中的元素的数量。您可以将此数字除以元素的高度,以获得如下所示的百分比:

var percentage = (windowBottom - elementTop) / $(".element").height() * 100;

试试下面的代码段或查看 CodePen Demo

&#13;
&#13;
$(document).ready(function() {

  $(window).scroll(function() {
    var windowBottom = $(this).scrollTop() + $(this).height();
    var elementTop = $(".element").offset().top;
    var percentage = (windowBottom - elementTop) / $(".element").height() * 100;

    if (percentage >= 100) {
      $(".percent").text('100%');
    } else if (windowBottom >= elementTop) {
      $(".percent").text(`${Math.round(percentage)}%`);
    } else {
      $(".percent").text('0%');
    }
  });

});
&#13;
body {
  margin: 0;
  padding: 0;
  color: white;
}

.flex-layout {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.info-container {
  position: fixed;
  z-index: 1;
  font-size: 2em;
  height: 100%;
  width: 100%;
  color: white;
}

.block {
  height: 800px;
  background: #333;
}

.element {
  align-items: center;
  background: #000;
  height: 550px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class='info-container flex-layout'>
  <span>Scroll down</span>
  <span class='percent'>0%</span>
</div>


<div class='block'></div>
<div class='element flex-layout'>
  <span>Start</span>
  <span>End</span>
</div>
<div class='block'></div>
&#13;
&#13;
&#13;

我希望这会有所帮助,也是您正在寻找的。

答案 2 :(得分:1)

就像在stackoverflow上一样,可能只找到jQuery解决方案。而且我不喜欢jQuery。所以这里是:

**
 * @param {HTMLElement} element
 * @returns {number} percent of element in view
 */
function getPercentOfView(element) {
    const viewTop = window.pageYOffset;
    const viewBottom = viewTop + window.innerHeight;
    const rect = element.getBoundingClientRect();
    const elementTop = rect.top + viewTop;
    const elementBottom = elementTop + rect.height;

    if (elementTop >= viewBottom || elementBottom <= viewTop) {
        // heigher or lower than viewport
        return 0;
    } else if (elementTop <= viewTop && elementBottom >= viewBottom) { 
        // element is completely in viewport and bigger than viewport
        return 100;
    } else if (elementBottom <= viewBottom) {
        if (elementTop < viewTop) {
            // intersects viewport top
            return Math.round((elementBottom - viewTop) / window.innerHeight * 100);
        } else {
            // completely inside viewport
            return Math.round((elementBottom - elementTop) / window.innerHeight * 100);;
        }
    } else {
        // intersects viewport bottom
        //  elementBottom >= viewBottom && elementTop <= viewBottom
        return Math.round((viewBottom - elementTop) / window.innerHeight * 100);
    }
}