vue悬浮导航实现内容滚动时,导航跟随选中,点击导航滚动到相应位置,

在这里插入图片描述

<template>
    <div>
        <div class="goods_navBg" ref="navHeader">模拟悬浮导航</div>
        <div class="goods_box">box</div>
        <!-- 吸顶导航 start -->
        <GoodsInfoNavTab class="goods_sticky" :navHeaderHeight="navHeaderHeight" :tabTitle="tabTitle"></GoodsInfoNavTab>
        <!-- 吸顶导航 end -->
        <ul class="ulMain">
            <li class="goodsMBox" v-for="(item, index) in tabTitle" :key="index">{{ item }}</li>
        </ul>
    </div>
</template>
<script>
export default {
    name: 'goodsPage',
    data() {
        return {
            tabTitle: ['Tab1', 'Tab2', 'Tab3', 'Tab4'],//子导航
            navHeaderHeight: 0,//子导航高度
        }
    },
    mounted() {
        //获取悬浮导航的高度
        this.navHeaderHeight = this.$refs.navHeader.offsetHeight;
    },
    methods: {}
}
</script>
<style scoped>
.goods_navBg {
    width: 7.5rem;
    height: 0.88rem;
    background: red;
    z-index: 999;
    position: fixed;
    top: 0;
    left: 0;
    text-align: center;
    font-size: 0.4rem;
    line-height: 0.88rem;
    color: white;
}

.goods_box {
    width: 100%;
    height: 5rem;
    background: green;
    margin-top: 0.88rem;
    font-size: 1rem;
    text-align: center;
    line-height: 5rem;
}


.goods_sticky {
    position: sticky;
    top: 0.88rem;
    z-index: 99;
}

.ulMain {
    width: 100%;
}

.goodsMBox {
    height: 10rem;
    font-size: 0.5rem;
    color: white;
}

.ulMain li:nth-child(1) {
    background: blue;
}

.ulMain li:nth-child(2) {
    background: blueviolet;
}

.ulMain li:nth-child(3) {
    background: orange;
}

.ulMain li:nth-child(4) {
    background: pink;
}</style>

导航组件:

<template>
    <div>
        <ul class="goods_ceiling" ref="navTab">
            <a v-for="(item, index) in tabTitle" :key="index" @click="scrollToPosition(index)"
                :class="{ js_goods_ceilTitle: active == index }">
                <li class="goods_ceilTitle">{{ item }}</li>
            </a>
        </ul>
    </div>
</template>
<script>
export default {
    name: 'GoodsInfoNavTab',
    props: {
        tabTitle: {
            type: Array,
            default: () => []
        },
        navHeaderHeight: {
            type: Number,
            default: 0
        }
    },
    data() {
        return {
            active: 0,// 当前激活的导航索引
        }
    },
    mounted() {
        //监听页面滚动条事件
        window.addEventListener("scroll", this.onScroll);
    },
    destroy() {
        // 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
        window.removeEventListener("scroll", this.onScroll);
    },
    methods: {
        onScroll() {
            let navTabHeight = this.$refs.navTab.offsetHeight //获取子导航的高度
            let navHeaderHeight = this.navHeaderHeight //获取悬浮导航的高度
            // 获取所有锚点元素
            const navContents = document.querySelectorAll('.goodsMBox')
            // 所有锚点元素的 offsetTop
            const offsetTopArr = []
            navContents.forEach(item => {
                offsetTopArr.push(item.offsetTop)
            })
            // 获取当前文档流的 scrollTop
            const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
            // 定义当前点亮的导航下标
            let navIndex = 0
            for (let n = 0; n < offsetTopArr.length; n++) {
                // 如果 scrollTop 大于等于第 n 个元素的 offsetTop 则说明 n-1 的内容已经完全不可见
                // 那么此时导航索引就应该是 n 了
                if (scrollTop >= offsetTopArr[n] - navTabHeight - navHeaderHeight) {
                    navIndex = n
                }
            }
            // 把下标赋值给 vue 的 data
            this.active = navIndex

        },
        scrollToPosition(index) {
            let navTabHeight = this.$refs.navTab.offsetHeight //获取子导航的高度
            let navHeaderHeight = this.navHeaderHeight //获取悬浮导航的高度
            // 获取目标的 offsetTop
            // css选择器是从 1 开始计数,我们是从 0 开始,所以要 +1
            const targetOffsetTop = document.querySelector(`.goodsMBox:nth-child(${index + 1})`).offsetTop - navTabHeight - navHeaderHeight
            // 获取当前 offsetTop
            let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
            // 定义一次跳 50 个像素,数字越大跳得越快,但是会有掉帧得感觉,步子迈大了会扯到蛋
            const STEP = 50
            // 判断是往下滑还是往上滑
            if (scrollTop > targetOffsetTop) {
                // 往上滑
                smoothUp()
            } else {
                // 往下滑
                smoothDown()
            }
            // 定义往下滑函数
            function smoothDown() {
                // 如果当前 scrollTop 小于 targetOffsetTop 说明视口还没滑到指定位置
                if (scrollTop < targetOffsetTop) {
                    // 如果和目标相差距离大于等于 STEP 就跳 STEP
                    // 否则直接跳到目标点,目标是为了防止跳过了。
                    if (targetOffsetTop - scrollTop >= STEP) {
                        scrollTop += STEP
                    } else {
                        scrollTop = targetOffsetTop
                    }
                    document.body.scrollTop = scrollTop
                    document.documentElement.scrollTop = scrollTop
                    // 屏幕在绘制下一帧时会回调传给 requestAnimationFrame 的函数
                    // 关于 requestAnimationFrame 可以自己查一下,在这种场景下,相比 setInterval 性价比更高
                    requestAnimationFrame(smoothDown)
                }
            }
            // 定义往上滑函数
            function smoothUp() {
                if (scrollTop > targetOffsetTop) {
                    if (scrollTop - targetOffsetTop >= STEP) {
                        scrollTop -= STEP
                    } else {
                        scrollTop = targetOffsetTop
                    }
                    document.body.scrollTop = scrollTop
                    document.documentElement.scrollTop = scrollTop
                    requestAnimationFrame(smoothUp)
                }
            }

        },
    }
}
</script>
<style lang="less" scoped>
.goods_ceiling {
    width: 7.5rem;
    height: 1rem;
    background: white;
    .flex_item;
    .f32;
    justify-content: space-around;
}

.goods_ceiling a {
    .c;
}

.goods_ceilTitle {
    height: 1rem;
    line-height: 1rem;
    text-align: center;
}

.js_goods_ceilTitle {
    font-weight: bold;
    position: relative;
}

.js_goods_ceilTitle::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    margin-left: -0.3rem;
    width: 0.6rem;
    height: 0.08rem;
    border-radius: 0.18rem;
    background: @c3b8;
}
</style>
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,您想了解关于网站导航设计与页面设计的内容,我可以为您介绍一下。 网站导航设计是指设计网站的各个页面之间的链接关系,使用户能够快速准确地找到所需内容。良好的导航设计可以提高用户体验,减少用户的迷失感和不确定性,从而提高网站的访问量和转化率。网站导航设计需要考虑以下几个方面: 1.导航位置:通常将导航放在网站的顶部或左侧比较合适,这样用户可以更方便地找到导航。 2.导航样式:可以采用下拉菜单、标签页等方式来展示导航,要注意导航样式的美观性和易用性。 3.导航分类:将网站内容按照逻辑分类,设计出合理的导航结构,使用户可以迅速找到所需内容。 页面设计是指设计网站的各个页面,包括页面布局、颜色搭配、文字排版、图片选择等方面,旨在提高用户的阅读体验和视觉感受。页面设计需要考虑以下几个方面: 1.布局设计:页面布局要合理,主次分明,让用户可以快速找到所需内容。 2.色彩搭配:选择合适的颜色搭配可以增强视觉效果,吸引用户的眼球。 3.字体排版:字体要选择清晰易读的字体,并考虑字体的大小、颜色、间距等问题。 4.图片选择:选择高质量的图片,符合页面风格,能够增强用户的视觉感受。 以上是网站导航设计与页面设计的简单介绍,希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值