开发者

Fire JavaScript Event When a DIV is in View

Is it possible to fire a specific JavaScript event when a certain DIV comes into view on the page?

Say, for example, I have a very large page, like 25开发者_StackOverflow中文版00x2500 and I have a 40x40 div that sits at position 1980x1250. The div is not necessarily manually positioned, it could be there due to the content pushing it there. Now, is it possible to run a function when the user scrolls to a point where the div becomes visible?


Not automatically. You would have to catch scroll events and check for it being in view each time by comparing the co-ordinates of the div rectangle with the visible page rectangle.

Here's a minimal example.

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

You could improve this by:

  • making it catch onscroll on all ancestors that have overflow scroll or auto and adjusting the top/left co-ords for their scroll positions
  • detecting overflow scroll, auto and hidden cropping putting the div off-screen
  • using addEventListener/attachEvent to allow multiple VisibilityMonitors and other things using the resize/scroll events
  • some compatibility hacks to getElementRect to make the co-ords more accurate in some cases, and some event unbinding to avoid IE6-7 memory leaks, if you really need to.


Here is a solution that is ideal in 2022. The current top answer only allows you to observe one item, and has performance issues because it fires many times every time the page scrolls.

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"));

This fires as soon as the item is partially on screen. Changing threshold to 1 will require the item to be fully on screen (so it will never fire if the item is bigger than the viewport). You can do values in between for example 0.25 to fire when at least 1/4 of the item is in view.


Here's an starter example using 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>

It only notifies once the div comes into view from the bottom. This example does not notify when the div scrolls out of the top.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜