如何在JavaScript中实现“onVisible”事件?

27

有没有一种或一组技术可以用来在JavaScript中实现类似于onVisible的“事件”?

我想让我的JavaScript检测网页中的元素(如文字段落或图像)何时在用户向下滚动页面时在浏览器窗口中变为可见。我还希望对应的“事件”onNotVisible在一个曾经在浏览器窗口中可见的元素不再可见时触发。

如果无法轻松地在JavaScript中实现,是否有任何特定于浏览器的事件可以提供相同的功能?


也许这会对你有所帮助:https://dev59.com/sXRC5IYBdhLWcg3wJNcN - user372551
2
请看:https://dev59.com/FHRB5IYBdhLWcg3w3K4J - edbond
3个回答

9

我必须亲自尝试一下,并得出了以下结论:

<!DOCTYPE html>
<html>
<head>
<script>

var EventListener = function(element, callback) {
    this._el = element;
    this._cb = callback;
    this._at = false;
    this._hasBeenVisible = false;
    this._hasBeenInvisible = true;
    var  _me = this;

    window.onscroll = function() {
        for (q in EventListener.queue.onvisible) {
            EventListener.queue.onvisible[q].call();
        }
        for (q in EventListener.queue.oninvisible) {
            EventListener.queue.oninvisible[q].call();
        }
    };

    return {
        onvisible: function() {
            EventListener.queue.onvisible.push(function() {
                if (!_me._at && _me._hasBeenInvisible && (window.pageYOffset + window.innerHeight) > _me._el.offsetTop && window.pageYOffset < (_me._el.offsetTop + _me._el.scrollHeight)) {
                    _me._cb.call();
                    _me._at = true;
                    _me._hasBeenVisible = true;
                }
            });
            EventListener.queue.oninvisible.push(function() {
                if (_me._hasBeenVisible && ((window.pageYOffset + window.innerHeight) < _me._el.offsetTop || window.pageYOffset > (_me._el.offsetTop + _me._el.scrollHeight))) {
                    _me._hasBeenInvisible = true;
                    _me._hasBeenVisible   = false;
                    _me._at = false;
                }
            });
        },
        oninvisible: function() {
            EventListener.queue.oninvisible.push(function() {
                if (!_me._at && _me._hasBeenVisible && ((window.pageYOffset + window.innerHeight) < _me._el.offsetTop || window.pageYOffset > (_me._el.offsetTop + _me._el.scrollHeight))) {
                    _me._cb.call();
                    _me._at = true;
                    _me._hasBeenInvisible = true;
                }
            });
            EventListener.queue.onvisible.push(function() {
                if (_me._hasBeenInvisible && (window.pageYOffset + window.innerHeight) > _me._el.offsetTop && window.pageYOffset < (_me._el.offsetTop + _me._el.scrollHeight)) {
                    _me._hasBeenVisible = true;
                    _me._hasBeenInvisible = false;
                    _me._at = false;
                }
            });
        }
    };
}
EventListener.queue = {
    onvisible:   [],
    oninvisible: []
};

function addListener(element, event, fn) {
    if (typeof element == 'string')
        element = document.getElementById(element);

    var listener = new EventListener(element, fn);

    if (listener['on' + event.toLowerCase()])
        return listener['on' + event.toLowerCase()].call();
}

window.onload = function() {
    addListener('event-element', 'visible', function() {
        alert("Element One Visible!");
    });
    addListener('event-element', 'invisible', function() {
        alert("Element One Invisible!");
    });
    addListener('event2-element', 'visible', function() {
        alert("Element Two Visible!");
    });
    addListener('event2-element', 'invisible', function() {
        alert("Element Two Invisible");
    });
}

</script>
</head>
<body>

<h1>Hey!</h1>

<div style="height: 1500px;">
Please scroll down some pixels.
</div>

<p id="event-element">
    This element should cast an event 'onvisible' and 'oninvisible'.
</p>

<div style="height: 1000px;">

</div>

<p id="event2-element">
    Another one!
</p>


</body>
</html>

测试环境:

  • FireFox 3.6(可用)
  • Chrome 6.0.472(可用)
  • Opera 10.62(可用)
  • Safari 4(以非常错误和令人烦恼的方式工作,如果在此处尝试,请勿使用弹出窗口!)

代码也可以在PasteBin上找到

以上代码没有进行任何优化,我只是开始编写,直到它能够工作。最好您可能只想使用一个队列,重构一些代码并使其更通用。按原样提供。


1
好的答案。但这并不考虑显示属性!需要遍历元素的parentNode并检查它们所有的显示属性是否可见。非常适用于按需内容加载。 - Lorenz Lo Sauer

8

您需要为文档或窗口的onscroll事件设置一个事件侦听器。然后,您需要通过将clientHeight添加到scrollTop来测量当前可见区域,然后检查您选择的元素是否在该区域内。类似下面的代码:

myElem=document.getElementById('some_id');
scrollOffset=document.getElementsByTagName('html')[0].scrollTop;
visibleHeight=document.getElementsByTagName('html')[0].clientHeight;
if(myElem.offsetTop>=scrollOffset && myElem.offsetTop<=scrollOffset+visibleHeight){
    // element is in visible area
}

如果是这种情况,你需要在代码中设置一些标志。

但是你可能会遇到浏览器不兼容的问题,所以最好使用一些库。


如何检查所选元素是否在此区域内? - RobertG

4

在上面@edbond提到的问题中,其中一个答案指向了jQuery的appear插件。该插件允许您将appeardisappear回调附加到一个元素上,当元素滚动进入和离开视图时被调用,这似乎正是您正在寻找的。


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