滚动内容区域高亮对应菜单栏

1,016 阅读1分钟

记录一下有意思的思路

上班遇到需要完成列表滚动并高亮对应菜单栏的需求

202210161038.gif

滚动思路:先获取列表的每一项小容器的offsetTop和浏览器滚动条的滚动高度相减,得到每一个相减的绝对值,绝对值越小就说明该容器越接近当前显示的屏幕区域,再根据该下标就可以知道当前需要高亮的菜单栏是哪一项。

菜单点击思路:获取菜单栏当前点击的index,滚动到对应的列表的offsetTop即可

直接上代码

<template>
    <div class="content-container">
        <div class="aside">
            <el-menu :default-active="activeIndex" class="el-menu-vertical-demo aside-menu" @select="handleSelect">
                <el-menu-item index="0">
                    <i class="el-icon-menu"></i>
                    <span slot="title">导航一</span>
                </el-menu-item>
                <el-menu-item index="1">
                    <i class="el-icon-menu"></i>
                    <span slot="title">导航二</span>
                </el-menu-item>
                <el-menu-item index="2">
                    <i class="el-icon-document"></i>
                    <span slot="title">导航三</span>
                </el-menu-item>
                <el-menu-item index="3">
                    <i class="el-icon-setting"></i>
                    <span slot="title">导航四</span>
                </el-menu-item>
            </el-menu>
        </div>

        <div class="content">
            <div class="box" ref="content">
                <div class="item" :id="`item${index}`" v-for="(item, index) in contentList">{{ item }}</div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: 'Content',
    data() {
        return {
            contentList: ['1', '2', '3', '4'],
            activeIndex: '0',
            content: ''
        }
    },
    methods: {
        /**
         * 滚动事件
         */
        handleScroll(e) {
            /* *
             * 获取每个.item的offsetTop
             * 与滚动高度相减的绝对值的下标和哪个菜单栏index最近
             * 就高亮哪个菜单项
             * */
            let scroll = this.$refs.content.scrollTop
            let arr = Array(4)
                .fill(0)
                .map((item, index) => {
                    let contentItem = document.getElementById(`item${index}`)
                    return Math.abs(scroll - contentItem.offsetTop)
                })
            this.activeIndex = arr.indexOf(Math.min(...arr)) + ''
        },
        handleSelect(index) {
            let contentItem = document.getElementById(`item${index}`)
            this.$refs.content.scrollTo({
                top: contentItem.offsetTop,
                behavior: 'smooth'
            })
        }
    },
    mounted() {
        this.$nextTick(() => {
            this.$refs.content.addEventListener('scroll', this.handleScroll)
        })
    },
    beforeDestroy() {
        this.$refs.content.removeEventListener('scroll', this.handleScroll)
    }
}
</script>

<style scoped>
.content-container {
    display: flex;
    justify-content: space-between;
    overflow: hidden;
}
.aside {
    width: 200px;
}
.aside-menu {
    position: fixed;
    top: 0;
    left: 0;
    width: 200px;
    height: 100vh;
}
.content {
    flex: 1;
    font-size: 32px;
    text-align: center;
    overflow: hidden;
}
.content .box {
    width: 100%;
    height: 100vh;
    overflow: auto;
}
.content .box .item {
    height: 900px;
    background: #ec4141;
    margin-bottom: 10px;
}
</style>