页面元素滚动真实展现

来源:互联网 发布:intent的传递数据 编辑:程序博客网 时间:2024/05/22 20:27

最近遇到一个情况,页面上存在一个很长的列表,超出了浏览器的高度,也就是说有一部分列表元素是存在于浏览器可视范围之外的,需求是单独针对每一个列表项,当某列表项因为滚动条的滚动而出现在可视范围内时,则记录一次。


需求的关键在于监听判断列表项是否出现在浏览器可视范围内,这里为了简化操作,使用了 jQuery库.
元素相对于浏览器可视区域共有三种情况:

  1. 向上滚动超出可见区域
  2. 向下滚动超出可视区域
  3. 在可视区域内

对于上述情况,需要三个高度值来确定:

  1. 元素距离页面顶部的距离
    $(".item").offset().top
  2. 元素本身的高度
    $(".item").outerHeight()
  3. 页面滚动的距离
    $(window).scrollTop()

上述两段结合,得到如下两种元素在可是区域内的结论:

  1. 向上滚动超出可见区域
    整个页面滚动的距离 > (元素顶部偏移量 + 元素本身的高度)
  2. 向下滚动超出可视区域
    整个页面滚动的距离 < (元素顶部偏移量 - 浏览器可见区域高度)

不符合上述两种情况的,则可以判断元素在可视区域内,初步代码如下:

var $win = $(window);var itemOffsetTop = $(".item").offset().top;var itemOuterHeight = $(".item").outerHeight();var winHeight = $win.height();var winScrollTop = $win.scrollTop();if(!(winScrollTop > itemOffsetTop+itemOuterHeight) &&   !(winScrollTop < itemOffsetTop-winHeight)){    // dosomething}

封装成函数方便调用:

// 获取元素是否真实展现const isCateVisible = ($ele, winH, itemOuterHeight) => {  let winScrollTop = $(window).scrollTop()  let itemOffsetTop = $ele.offset().top  // 最好把这两个值传入,避免重复获取  winH === undefined && (winH = $(window).height())  itemOuterHeight === undefined && (itemOuterHeight = $ele.height())  return winScrollTop < itemOffsetTop + itemOuterHeight && winScrollTop > itemOffsetTop - winH}

基于以上,我们就可以实现在页面滚动的时候,实时获取长列表项中每条列表项是否存在于浏览器可视区域内的信息。

$(function(){ var $win = $(window); var winHeight = $win.height(); var itemOuterHeight = $("li").outerHeight() $win.scroll(function () {    var winScrollTop = $win.scrollTop();    $("li").each(function(index) {    if(isCateVisible($(this), winHeight, itemOuterHeight)) {        // 元素已真实展现    }  }) })})

以上代码足以达到目的,但是还可以继续优化一下,比如控制scroll监听事件的触发频率,已经出现在可视区域内的元素,以后就不用再继续处理了,当所有的列表项全都展示完毕后,清除监听器。

$(function(){  var $win = $(window);  var itemOuterHeight = $("li").outerHeight();  var notShow = {}  var winHeight = $win.height();  var timeout = null  // 提前缓存所有列表项的高度  $("li").each(function(index) {    notShow[index] = $(this).outerHeight()  })  // 监听器函数  function scrollFn(){    if (timeout) {      clearTimeout(timeout)    }    // 控制频率    timeout = setTimeout(function () {      var winScrollTop = $win.scrollTop();      var itemOffsetTop = 0;      $("li").each(function(index) {        itemOffsetTop = $(this).offset().top        if(notShow[index] && isCateVisible($(this), winHeight, itemOuterHeight)) {          // dosomething           console.log(index);          delete notShow[index];          if ($.isEmptyObject(notShow)) {            // 清除监听器            $win.unbind('scroll', scrollFn);          }        }      })    }, 20)  }  // 绑定监听器  $win.bind('scroll', scrollFn)})