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
Check if element is between 30% and 60% of the viewport
提问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:
所以我有这样的元素网格并排堆叠:
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 :
我正在使用一个非常简单的结构:
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
- Use
scroll
event handler onwindow
- Loop over all the
li
elements to check if the element is in the interested viewport - Get the
li
position fromtop
and check if it is in the interested viewport section.
- 使用
scroll
事件处理程序window
- 循环遍历所有
li
元素以检查元素是否在感兴趣的视口中 - 获取
li
位置top
并检查它是否在感兴趣的视口部分。
Changed the height of li
for 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.
还改进了示例的图形以突出显示感兴趣的区域。
$(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>
回答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
我没有测试它,但我希望它有效