在视口中可以看到多少元素

时间:2015-11-22 20:02:59

标签: javascript jquery

页面上有div(棕色矩形)。页面高于视口(橙色矩形),因此可以滚动它,这意味着div可能只是部分显示或根本不显示。

element visibility

什么是最简单的算法来判断视口中div的百分比是多少?

(为了简化操作,div始终水平放入视口,因此在计算时只需要考虑Y轴。)

5 个答案:

答案 0 :(得分:18)

在小提琴中再看一个例子: https://jsfiddle.net/1hfxom6h/3/

=/2
/*jslint browser: true*/
/*global jQuery, window, document*/
(function ($) {
    'use strict';
    var results = {};

    function display() {
        var resultString = '';

        $.each(results, function (key) {
            resultString += '(' + key + ': ' + Math.round(results[key]) + '%)';
        });

        $('p').text(resultString);
    }

    function calculateVisibilityForDiv(div$) {
        var windowHeight = $(window).height(),
            docScroll = $(document).scrollTop(),
            divPosition = div$.offset().top,
            divHeight = div$.height(),
            hiddenBefore = docScroll - divPosition,
            hiddenAfter = (divPosition + divHeight) - (docScroll + windowHeight);

        if ((docScroll > divPosition + divHeight) || (divPosition > docScroll + windowHeight)) {
            return 0;
        } else {
            var result = 100;

            if (hiddenBefore > 0) {
                result -= (hiddenBefore * 100) / divHeight;
            }

            if (hiddenAfter > 0) {
                result -= (hiddenAfter * 100) / divHeight;
            }

            return result;
        }
    }

    function calculateAndDisplayForAllDivs() {
        $('div').each(function () {
            var div$ = $(this);
            results[div$.attr('id')] = calculateVisibilityForDiv(div$);
        });

        display();
    }

    $(document).scroll(function () {
        calculateAndDisplayForAllDivs();
    });

    $(document).ready(function () {
        calculateAndDisplayForAllDivs();
    });
}(jQuery));
div {
    height:200px;
    width:300px;

    border-width:1px;
    border-style:solid;
}
p {
    position: fixed;
    left:320px;
    top:4px;
}

答案 1 :(得分:3)

在玩了一下之后,我想我可能找到了最简单的方法:我基本上确定了元素在视口上延伸了多少(在哪个方向上并不重要)并且基于此它可以很容易地计算出多少可见。



// When the page is completely loaded.
$(document).ready(function() {

  // Returns in percentages how much can be seen vertically
  // of an element in the current viewport.
  $.fn.pvisible = function() {
    var eTop = this.offset().top;
    var eBottom = eTop + this.height();
    var wTop = $(window).scrollTop();
    var wBottom = wTop + $(window).height();
    var totalH = Math.max(eBottom, wBottom) - Math.min(eTop, wTop);
    var wComp = totalH - $(window).height();
    var eIn = this.height() - wComp;
    return (eIn <= 0 ? 0 : eIn / this.height() * 100);
  }

  // If the page is scrolled.
  $(window).scroll(function() {
    // Setting the opacity of the divs.
    $("div").each(function() {
      $(this).css("opacity", Math.round($(this).pvisible()) / 100);
    });
  });

});
&#13;
html,
body {
  width: 100%;
  height: 100%;
}
body {
  background-color: rgba(255, 191, 127, 1);
}
div {
  width: 60%;
  height: 30%;
  margin: 5% auto;
  background-color: rgba(175, 153, 131, 1);
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
&#13;
&#13;
&#13;

帮助了解其工作原理的一个小插图:

enter image description here

答案 2 :(得分:2)

这是一个说明如何计算此内容的片段。

我已将%值放在方框中以便于阅读,它甚至有点&#34;跟随&#34;视口^^:

Fiddle version

&#13;
&#13;
function listVisibleBoxes() {

  var results = [];

  $("section").each(function () {

    var screenTop = document.documentElement.scrollTop;
    var screenBottom = document.documentElement.scrollTop + $(window).height();
    var boxTop = $(this).offset().top;
    var boxHeight = $(this).height();
    var boxBottom = boxTop + boxHeight;

    if(boxTop > screenTop) {
      if(boxBottom < screenBottom) {
        //full box
        results.push(this.id + "-100%");
        $(this).html("100%").css({ "line-height": "50vh" });
      } else if(boxTop < screenBottom) {
        //partial (bottom)
        var percent = Math.round((screenBottom - boxTop) / boxHeight * 100) + "%";
        var lineHeight = Math.round((screenBottom - boxTop) / boxHeight * 50) + "vh";
        results.push(this.id + "-" + percent);
        $(this).html(percent).css({ "line-height": lineHeight });
      }
    } else if(boxBottom > screenTop) {
      //partial (top)
      var percent = Math.round((boxBottom - screenTop) / boxHeight * 100) + "%";
      var lineHeight = 100 - Math.round((boxBottom - screenTop) / boxHeight * 50) + "vh";
      results.push(this.id + "-" + percent);
      $(this).html(percent).css({ "line-height": lineHeight });
    }
  });

  $("#data").html(results.join(" | "));

}

$(function () {

  listVisibleBoxes();

  $(window).on("scroll", function() {
    listVisibleBoxes();
  });

});
&#13;
body {
  background-color: rgba(255, 191, 127, 1);
  font-family: Arial, sans-serif;
}

section {
  background-color: rgba(175, 153, 131, 1);
  height: 50vh;
  font-size: 5vh;
  line-height: 50vh;
  margin: 10vh auto;
  overflow: hidden;
  text-align: center;
  width: 50vw;
}

#data {
  background-color: rgba(255, 255, 255, .5);
  left: 0;
  padding: .5em;
  position: fixed;
  top: 0;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<section id="one"></section>
<section id="two"></section>
<section id="three"></section>
<section id="four"></section>
<section id="five"></section>
<section id="six"></section>

<div id="data">data here</div>
&#13;
&#13;
&#13;

答案 3 :(得分:1)

Chrome现在支持Intersection Observer API:
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

示例(TypeScript):

export const elementVisibleInPercent = (element: HTMLElement) => {
    return new Promise((resolve, reject) => {
        const observer = new IntersectionObserver((entries: IntersectionObserverEntry[]) => {
            entries.forEach((entry: IntersectionObserverEntry) => {
                resolve(Math.floor(entry.intersectionRatio * 100));
                clearTimeout(timeout);
                observer.disconnect();
            });
        });

        observer.observe(element);
        // Probably not needed, but in case something goes wrong.
        const timeout = setTimeout(() => {
            reject();
        }, 500);
    });
};

const example = document.getElementById('example');
const percentageVisible = elementVisibleInPercent(example);

示例(JavaScript):

export const elementVisibleInPercent = (element) => {
    return new Promise((resolve, reject) => {
        const observer = new IntersectionObserver(entries => {
            entries.forEach(entry => {
                resolve(Math.floor(entry.intersectionRatio * 100));
                clearTimeout(timeout);
                observer.disconnect();
            });
        });

        observer.observe(element);
        // Probably not needed, but in case something goes wrong.
        const timeout = setTimeout(() => {
            reject();
        }, 500);
    });
};

const example = document.getElementById('example');
const percentageVisible = elementVisibleInPercent(example);

答案 4 :(得分:-1)

请注意,Intersection Observer API从那时起就可以使用,这是专门为此目的而设计的。