Javascript滚动页面获取当前视窗模块的锚点的代码

Web前端开发 / 14 次阅读

常用的功能,当前页面模块锚点菜单固定跟随,当窗口滚动到某个模块时,当前锚点菜单高亮显示。思路是先获取每个模块距离顶部的大小,存到一个数组里,滚动的时候获取滚动的距离,再遍历数组对比当前滚动距离的值,如果大于滚动距离的值,就是当前锚点。或者每滚动一次,就遍历获取各锚点模块距离顶部的大小一次,再进行对比,但感觉这样性能会差很多,推荐前者。

Javascript滚动页面获取当前视窗模块的锚点的代码

HTML代码:

<div id="wrapper">
    <nav id="menu">
        <ul class="set-mp">
            <li data-item="module-1">
                <a href="javascript:void(0);">模块一</a>
            </li>
            <li data-item="module-2">
                <a href="javascript:void(0);">模块二</a>
            </li>
            <li data-item="module-3">
                <a href="javascript:void(0);">模块三</a>
            </li>
            <li data-item="module-4">
                <a href="javascript:void(0);">模块四</a>
            </li>
        </ul>
    </nav>
    <main id="module">
        <section class="module-item" data-module="module-1" style="background-color: #b9925a;">
            模块一
        </section>
        <section class="module-item" data-module="module-2" style="background-color: #eee;">
            模块二
        </section>
        <section class="module-item" data-module="module-3" style="background-color: #efc;">
            模块三
        </section>
        <section class="module-item" data-module="module-4" style="background-color: #fa7;">
            模块四
        </section>
    </main>
</div>

CSS代码:

/*html*/
html {font-size:100px;}
/*wrapper*/
#wrapper {
    padding:0.5rem;
}
/*menu*/
#menu {
    margin-bottom: 0.5rem;
    position: sticky;
    top:0.1rem;
    z-index: 10;
    ul {
        margin:0; 
        display: flex;
    }
    li {
        margin-right: 0.2rem;
    }
    a {
        display: block;
        background-color: #f6f6f6;
        color:#333;
        width: 5em;
        height: 2.5em;
        line-height: 2.5em;
        text-align: center;
    }
    .current {
        a {
            background-color:#b9925a;
            color:#fff;
        }
    }
}
/*module*/
#module {
    .module-item {
        height: 30vw;
    }
}

JS代码:

<script>
let $module = document.querySelectorAll('.module-item');
let $element = [];
$module.forEach(element => {
    let $moduleName = element.dataset.module;
    let $offsetTop = element.offsetTop - window.innerHeight/2;
    $element.push({top:$offsetTop, module:$moduleName});
});
let $lastScrollY = window.scrollY;
let $currentElement;
function scrollHandler(){
    let $currentScrollY = window.scrollY;  
    if(Math.abs($currentScrollY - $lastScrollY) > 0){
        $element.forEach(element=>{
            if($currentScrollY > element.top){
                $currentElement = element.module;
                $selector = '[data-item="'+element.module+'"]';
                document.querySelector($selector).classList.add('current');
                //$($selector).addClass('current').siblings('li').removeClass('current'); 如果使用jQuery,下面那个遍历就不需要了
            }
        });
        $element.forEach(element=>{
            if(element.module != $currentElement){
                $selector = '[data-item="'+element.module+'"]';
                document.querySelector($selector).classList.remove('current');
            }
        });
        $lastScrollY = $currentScrollY;
    }
    requestAnimationFrame(scrollHandler);
}
requestAnimationFrame(scrollHandler);
</script>

也可以按思路使用jQuery写,换成scroll()代码数量可以省一点。