我已经创建了一个元素数组,我想在窗口滚动时不断循环,检查元素是否可见,如果可见,将其设置为活动,然后我想从数组中删除这个元素,最终检查数组是否为空,以解除滚动事件的绑定。
目前我很难知道应该用什么方式去除这个元素?我目前正在使用:
var index = innerItems.index($thisEl.index());
innerItems.splice(index, 1);
然而,这似乎把我用来检查视图中元素的函数搞砸了,我的数组长度似乎永远不会改变。
有人能推荐我如何实现我的目标,即在每个元素变为活动时删除它,直到我的数组为空并解除滚动事件的绑定吗?此外,如果有人能提供任何改进,那将是惊人的。
代码笔http://codepen.io/styler/pen/zDJrx
JS
var $mainContainer = $('.main-container'),
innerItems = $mainContainer.children();
function isElementInViewport (el) {
//special bonus for those using jQuery
if (typeof jQuery === "function" && el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
);
}
function init() {
itemChecker();
}
init();
$(window).on('scroll.windowScroll', itemChecker);
function itemChecker() {
innerItems.each(function(i, element) {
console.log('Index', i);
console.log('Element', element);
var $thisEl = $(element);
// if isElementInViewport then add class is-active and remove from innerItems array
var inView = isElementInViewport(element);
if( inView ) {
$thisEl.addClass('is-active');
// Remove each element as it becomes ready/in view
var index = innerItems.index($thisEl.index());
innerItems.splice(index, 1);
}
console.log('innerItems length', innerItems.length);
if( innerItems.length === 0 ) {
$(window).off('scroll.windowScroll');
}
});
}
您的循环中有一个缺陷。你不能循环使用.each并移除循环中的项目。循环将期望初始项数,当涉及到被删除的索引时,它将抛出未定义的错误。
在这种情况下,应该使用基本上从数组末尾到开头的反向循环。或者正常循环,但在从数组中删除项的情况下更新索引变量。
反循环示例:
for (var i=arr.length;i--;) {
if (i%2==0) {
arr.splice(i, 1);
// We removed the item but this will not
// interfere with our counting as we are doing it in reverse
}
}
带索引更新的正常循环示例:
for (var i=0,len=arr.length;i<len;i++) {
if (i%2==0) {
arr.splice(i, 1);
// We removed the item from the array and we need to decrease it's length by one
len--;
}
}
回到你的例子,这里有一个更新的版本,在这里用固定代码分叉代码笔。。
var $mainContainer = $('.main-container'),
innerItemsCache = $mainContainer.children(),
innerItemsVisible;
function isElementInViewport (el) {
//special bonus for those using jQuery
if (typeof jQuery === "function" && el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
);
}
function init() {
itemChecker();
}
init();
$(window).on('scroll.windowScroll', itemChecker);
function itemChecker() {
innerItemsVisible = [];
for (var i=innerItemsCache.length; i--;) {
console.log('Index', i);
console.log('Element', element);
var element = innerItemsCache[i];
var $thisEl = $(element);
// if isElementInViewport then add class is-active and remove from innerItems array
var inView = isElementInViewport(element);
if( inView ) {
$thisEl.addClass('is-active');
// Add elements that are visible
innerItemsVisible.push(innerItemsCache[i]);
} else {
$thisEl.removeClass('is-active');
}
console.log('innerItems length', innerItemsVisible.length);
}
if( innerItemsVisible.length === 0 ) {
$(window).off('scroll.windowScroll');
}
}
正如您所看到的,我添加了一个缓存数组,这样您就不必在每次迭代中搜索所有项目。同时,由于您已经在遍历所有项目,因此更容易创建空数组并用可见项目填充它,如本工作示例中所示。。
如果可以使用jquery路点插件,您可以实现与相同的功能
$('.inner-container').waypoint(function () {
$(this).addClass('is-active');
if($(this).is(".inner-container:last-child")){
alert("last item in view, destroying the functionality as you mentioned in comments");
$(this).waypoint('destroy');
}
}, {
offset: 'bottom-in-view'
});
* {
box-sizing:border-box
}
body {
padding:0;
margin:0
}
.main-container {
}
.inner-container {
background: rgba(255, 0, 0, .4);
width: 100%;
height: 200px;
border: 10px solid white;
}
.inner-container.is-active {
background: rgba(255, 0, 0, .7);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/waypoints/2.0.3/waypoints.min.js"></script>
<div class="main-container">
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
<div class="inner-container"></div>
</div>