检查元素是否在视口的30%和60%之间

36

我正在尝试在视口的30%到60%之间更改<li>元素的颜色。

所以我有一系列像这样并排堆叠的元素:

elements stacking side by side

我尝试了一些插件,如Waypoints、Viewport Checker和其他一些插件,但都不是很好用。

有什么建议吗?

我使用的是非常简单的结构:

JSFIDDLE

HTML

<!doctype html>

<html lang="en">

<head>
    <meta charset="utf-8">

    <title></title>
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="stylesheet" href="css/reset.css">
    <link rel="stylesheet" href="css/styles.css">
    <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
    <script src="js/main.js"></script>
    <!--[if lt IE 9]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  <![endif]-->
</head>

<body>
    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</body>

</html>

CSS:

ul {
    margin: auto;
}
ul li {
    width: 300px;
    height: 200px;
    background: #f5f5f5;
    float: left;
    margin: 10px;
}

ul li.middleviewport{
    background:red;
}

请提供一些源代码以便进行工作。 - Andrea Ligios
很好的视觉问题,只需像@AndreaLigios提到的那样添加代码,你的问题就完美了。 - kemicofa ghost
我正在创建一个 JSFiddle!抱歉现在元素比较少,因为还处于早期阶段。 - Hook
5个回答

32
  1. window上使用scroll事件处理程序。
  2. 循环遍历所有的li元素,检查该元素是否在感兴趣的视口中。
  3. top获取li元素的位置,并检查它是否在感兴趣的视口部分内。

示例:

为了演示目的,更改了li的高度。

请参见代码中的注释。

$(document).ready(function() {
  // Get viewport height, gridTop and gridBottom
  var windowHeight = $(window).height(),
    gridTop = windowHeight * .3,
    gridBottom = windowHeight * .6;

  $(window).on('scroll', function() {
    // On each scroll check if `li` is in interested viewport
    $('ul li').each(function() {
      var thisTop = $(this).offset().top - $(window).scrollTop(); // Get the `top` of this `li`

      // Check if this element is in the interested viewport
      if (thisTop >= gridTop && (thisTop + $(this).height()) <= gridBottom) {
        $(this).css('background', 'red');
      } else {
        $(this).css('background', 'gray');
      }
    });
  });
});
ul {
  margin: 0;
  list-style-type: none;
  padding: 0;
}
ul li {
  width: 50px;
  height: 30px;
  background: #f5f5f5;
  float: left;
  margin: 10px;
  text-align: center;
  padding-top: 10px
}
ul li.middleviewport {
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
</ul>


9

优化了 @Tushar 的解决方案,使其能够在窗口大小调整后仍然正常工作(每次都需要重新计算视口范围,而不仅仅是在开始时),并使其开始时就高亮显示,无需滚动。

还稍微改进了示例的图形,以突出感兴趣的区域。

运行演示

$(document).ready(function() {
  $(window).on('scroll', function() {
    var windowHeight = $(window).height(),
      gridTop = windowHeight * .3,
      gridBottom = windowHeight * .6;
    $('ul li').each(function() {
      var thisTop = $(this).offset().top - $(window).scrollTop();

      if (thisTop > gridTop && (thisTop + $(this).height()) < gridBottom) {
        $(this).css('background', 'red');
      } else {
        $(this).css('background', 'silver');
      }
    });

  });
  $(window).trigger('scroll');
});
ul {
  margin: auto;
}
ul li {
  width: 300px;
  height: 10px;
  background: silver;
  float: left;
  margin: 10px;
  list-style: none;
}
ul li.middleviewport {
  background: red;
}
#viewportMask {
  position: fixed;
  top: 30%;
  bottom: 40%;
  left: 0;
  right: 0;
  background: red;
  opacity: 0.2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="viewportMask"></div>
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>


很好!如果用户永远不会调整窗口大小,这将变得有点慢。而不是触发“滚动”,您可以通过像这样调用回调来调用它function() {}()); - Tushar
$(window).on().trigger() 也可以被使用。 (链式调用) - rev

2

[[ 这个示例检查元素的任何部分是否在指定区域内。 ]]

当您拥有两个框的顶部和底部坐标时,可以通过检查以下内容来检查这两个框是否重叠:

box1.top < box2.bottom && box1.bottom > box2.top

在下面的例子中,box1 是窗口的 30%-60% 部分,而 box2 是每个列表项。加入防抖函数后,我们得到以下代码:

var timeout;
$(window).on("load scroll resize", function() {
  if (timeout) {
    clearTimeout(timeout);
  }
  timeout = setTimeout(function() {
    var $window = $(window),
      hitbox_top = $window.scrollTop() + $window.height() * .3,
      hitbox_bottom = $window.scrollTop() + $window.height() * .6;
    $("li").each(function() {
      var $element = $(this),
        element_top = $element.offset().top,
        element_bottom = $element.offset().top + $element.height();
      $element.toggleClass("middle-viewport", hitbox_top < element_bottom && hitbox_bottom > element_top);
    });
  }, 200);
});
#overlay {
  position: fixed;
  left: 0;
  top: 30%;
  width: 100%;
  height: 30%;
  background-color: rgba(0, 192, 255, .5);
}
ul {
  padding: 0;
  text-align: center;
}
li {
  display: inline-block;
  margin: 10px;
  width: 200px;
  height: 200px;
  background-color: #F5F5F5;
}
li.middle-viewport {
  background-color: #FF0000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="overlay"></div>
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>


1

我可以为此创建一个插件。在选项中,您可以设置百分比、CSS类、触发事件和执行延迟(CSS仅用于演示响应式):

jQuery.fn.extend({
 markInViewport: function (options) {
  var that = this;
  this.defaults = {
   percentTop: 30,
   percentBottom: 40,
   cssClass: 'middleviewport',
   event: 'scroll resize',
   delay: 10
  };
  this.options = $.extend(that.defaults, options);
  this.win = $(window);
  this.delayChecking = null;
  this.items = [];
  this.checkItems = function (items) {
   clearTimeout(that.delayChecking);
   that.delayChecking = setTimeout(function () {
    var thisWindowHeight = that.win.height();
    var thisWindowScrollTop = that.win.scrollTop();
    that.items.each(function (j) {
     var thisItem = $(this);
     var thisItemHeight = thisItem.outerHeight();
     var thisItemPositionTop = thisItem.offset().top;
     var currentPercentTop = (thisItemPositionTop - thisWindowScrollTop) / thisWindowHeight * 100;
     var currentPercentBottom = (thisWindowScrollTop + thisWindowHeight - thisItemPositionTop - thisItemHeight) / thisWindowHeight * 100;
     thisItem.toggleClass(that.options.cssClass, currentPercentTop >= that.options.percentTop && currentPercentBottom >= that.options.percentBottom);
    });
   }, that.options.delay);
  };
  return this.each(function () {
   that.items = that.children();
   $(window).on(that.options.event, that.checkItems);
   that.checkItems();
  });
 }
});
$('.check_viewport').markInViewport();
ul {
    margin: 0 auto;
    padding: 0;
}
ul li {
    width: 32.73%;
    height: 0;
    padding-bottom: 3.5%; /* responsive height */
    background: #f5f5f5;
    float: left;
    margin: .3%;
    list-style:none;
}
ul li.middleviewport {
    background:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
    <ul class="check_viewport">
        <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
    </ul>
</body>

在这里查看Fiddle


0
创建一个宽度为width:100%height:100%的div,代表视口。在这个div里面放置你的网格系统。
然后你需要使用jQuery的.position()jquery position
var grid = $( "griddiv's" );
var position = grid.position();
var height = $('parentdiv').height();
lower = 0.3 * height;
upper = 0.6 * height;

if(grid.top >= lower && grid.top <= upper){
  $('gridcell').css('background','red');
}

我没有测试过,但希望它能正常工作


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接