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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29891587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 11:15:12  来源:igfitidea点击:

Check if element is between 30% and 60% of the viewport

javascriptjqueryhtmlcssviewport

提问by Hook

I am trying to change the color of <li>elements when they are between 30% and 60% of the viewport.

<li>当元素位于视口的 30% 到 60% 之间时,我试图更改元素的颜色。

So I have this grid of elements stacking side by side like this:

所以我有这样的元素网格并排堆叠:

elements stacking side by side

元素并排堆叠

I ran into few plugins like Waypoints, Viewport Checker and few others but nothing good.

我遇到了一些插件,如 Waypoints、Viewport Checker 和其他一些插件,但都没有什么好处。

Any idea?

任何的想法?

I am using a pretty simple structure :

我正在使用一个非常简单的结构:

JSFIDDLE

JSFIDDLE

HTML

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:

CSS:

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

ul li.middleviewport{
    background:red;
}

采纳答案by Tushar

  1. Use scrollevent handler on window
  2. Loop over all the lielements to check if the element is in the interested viewport
  3. Get the liposition from topand check if it is in the interested viewport section.
  1. 使用scroll事件处理程序window
  2. 循环遍历所有li元素以检查元素是否在感兴趣的视口中
  3. 获取li位置top并检查它是否在感兴趣的视口部分。

Demo:

演示:

Changed the height of lifor demo purpose.

li出于演示目的更改了 的高度。

See the comments inline in the code.

请参阅代码中的内联注释。

$(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>

回答by Andrea Ligios

Improved @Tushar's solution to make it work even after a resize of the window (a recalculation of the viewport is necessary each time, not only at the beginning), and to make it start already highlighted, without the need to scroll.

改进了@Tushar 的解决方案,使其即使在调整窗口大小后也能工作(每次都需要重新计算视口,而不仅仅是在开始时),并且使其开始时已经突出显示,无需滚动。

Also improved a bit the graphic of the example to highlight the interested area.

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

Running demo

运行演示

$(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>

回答by Salman A

[[ This example checks if ANY part of the element is inside the specified region ]]

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

When you have the top and bottom coordinates of two boxes, you can check if the two boxes overlap by checking:

当你有两个框的顶部和底部坐标时,你可以通过检查来检查两个框是否重叠:

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

In the following example, box1 is the 30%-60% portion of window while box2 is each list item. Add debounce function and we have:

在以下示例中,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>

回答by skobaljic

I was free to create a plugin for this. Within options you can set percents, css class, trigger event and execution delay (css changed to responsive for presentation only):

我可以自由地为此创建一个插件。在选项中,您可以设置百分比、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 here

在这里摆弄

回答by Vinc199789

Create a div width width:100%and height:100%that represent the viewport. Inside this div you place your grid system.

创建一个 div 宽度width:100%height:100%代表视口。在这个 div 中,您可以放置​​网格系统。

Than you need to use jquery .position()jquery position

比你需要使用 jquery 的.position()jquery 位置

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');
}

I didn't test it but I hope it works

我没有测试它,但我希望它有效