当一个DIV在视图中时触发JavaScript事件

15

当某个 DIV 出现在页面上时,是否可能触发特定的 JavaScript 事件?

比如说,我有一个非常大的页面,像是 2500x2500,而我有一个大小为 40x40 的 DIV,它位于 1980x1250 的位置。这个 div 不一定是手动定位的,它可能是由于内容推动它到那里的。那么,当用户滚动到 div 可见的位置时,是否可能运行一个函数?


1
https://github.com/imakewebthings/waypoints 或 https://github.com/stutrek/scrollMonitor 也可能有所帮助。 - Adriano
3个回答

11

不是自动的。您需要捕捉滚动事件并每次通过比较div矩形的坐标与可见页面矩形来检查它是否在视图中。

这是一个最简示例。

<div id="importantdiv">hello</div>

<script type="text/javascript">
    function VisibilityMonitor(element, showfn, hidefn) {
        var isshown= false;
        function check() {
            if (rectsIntersect(getPageRect(), getElementRect(element)) !== isshown) {
                isshown= !isshown;
                isshown? showfn() : hidefn();
            }
        };
        window.onscroll=window.onresize= check;
        check();
    }

    function getPageRect() {
        var isquirks= document.compatMode!=='BackCompat';
        var page= isquirks? document.documentElement : document.body;
        var x= page.scrollLeft;
        var y= page.scrollTop;
        var w= 'innerWidth' in window? window.innerWidth : page.clientWidth;
        var h= 'innerHeight' in window? window.innerHeight : page.clientHeight;
        return [x, y, x+w, y+h];
    }

    function getElementRect(element) {
        var x= 0, y= 0;
        var w= element.offsetWidth, h= element.offsetHeight;
        while (element.offsetParent!==null) {
            x+= element.offsetLeft;
            y+= element.offsetTop;
            element= element.offsetParent;
        }
        return [x, y, x+w, y+h];
    }

    function rectsIntersect(a, b) {
        return a[0]<b[2] && a[2]>b[0] && a[1]<b[3] && a[3]>b[1];
    }

    VisibilityMonitor(
        document.getElementById('importantdiv'),
        function() {
            alert('div in view!');
        },
        function() {
            alert('div gone away!');
        }
    );
</script>

您可以通过以下方法改进:

  • 对具有overflow scrollauto的所有祖先元素捕获onscroll事件,并调整它们的滚动位置的顶部/左侧坐标。
  • 检测overflow scrollautohidden属性,将div放在屏幕外进行裁剪。
  • 使用addEventListener/attachEvent允许多个可见性监视器以及使用resize/scroll事件的其他功能。
  • 一些兼容性技巧对getElementRect进行修改,在某些情况下使坐标更准确,并且一些解除绑定事件以避免IE6-7内存泄漏(如果确实需要)。

你可以使用内置的element.getBoundingClientRect()替换掉getElementRect中的所有代码。 - V Maharajh

6

这里是一个在2022年非常理想的解决方案。当前最佳答案只能允许您观察一个项目,而且因为每次滚动页面时都会触发很多次,所以存在性能问题。

var observer = new IntersectionObserver(function(entries) {
    if(entries[0].isIntersecting === true) {
        console.log('Item has just APPEARED!');
    } else {
        console.log('Item has just DISAPPEARED!');
    }
}, { threshold: [0] });

observer.observe(document.querySelector("#DIV-TO-OBSERVE"));

此事件在项目部分显示在屏幕上时立即触发。将阈值更改为1将要求项目完全显示在屏幕上(因此如果项目大于视口,则永远不会触发)。您可以在中间使用值,例如0.25,以便当至少显示项目的四分之一时触发该事件。


0

以下是一个使用 jQuery 的入门示例:

<html>
<head><title>In View</title></head>
<body>
    <div style="text-align:center; font-size:larger" id="top"></div>
    <fieldset style="text-align:center; font-size:larger" id="middle">
        <legend id="msg"></legend>
        <div>&nbsp;</div>
        <div id="findme">Here I am!!!</div>
    </fieldset>
    <div style="text-align:center; font-size:larger" id="bottom"></div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js" type="text/javascript"></script>

<script type="text/javascript">
    var $findme = $('#findme'),
        $msg = $('#msg');

    function Scrolled() {
        var findmeOffset = $findme.offset(),
            findmeTop = findmeOffset.top,
            scrollTop = $(document).scrollTop(),
            visibleBottom = window.innerHeight;

        if (findmeTop < scrollTop + visibleBottom) {
            $msg.text('findme is visible');
        }
        else {
            $msg.text('findme is NOT visible');
        }
    }

    function Setup() {
        var $top = $('#top'),
            $bottom = $('#bottom');

        $top.height(500);
        $bottom.height(500);

        $(window).scroll(function() {
            Scrolled();
        });
    }

    $(document).ready(function() {
        Setup();

    });
</script>
</body>
</html>

只有在 div 从底部进入视图时才会发出通知。此示例在 div 滚动到顶部时不会发出通知。


再次强调,这是针对jQuery的,虽然我非常支持jQuery,但在我的情况下,我将无法使用它。 - Russ Bradberry
请注意,在提问中注明您的限制,这样发布帖子的人就会知道。而且似乎两个人几乎同时发表了帖子,所以他们不可能知道。 - Cryophallion
他们要求一个JavaScript解决方案,从未提到使用jQuery。这就好像有人要求一个PHP解决方案,你给他们一个只在Laravel中有效的东西,然后说“你应该列出你不使用的所有东西”。 - undefined

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