vue实现京东楼层效果
实现京东楼层效果的核心思路
京东楼层效果通常指页面滚动到特定位置时,对应楼层内容固定定位(sticky)并高亮导航菜单。Vue中可通过监听滚动事件、动态计算元素位置和结合CSS实现。
基础结构搭建
使用Vue 3的Composition API或Options API均可,以下以Composition API为例:
<template>
<div class="container">
<!-- 导航菜单 -->
<div class="nav">
<div
v-for="(item, index) in floors"
:key="index"
:class="{ active: currentFloor === index }"
@click="scrollTo(index)"
>
{{ item.name }}
</div>
</div>
<!-- 楼层内容 -->
<div
v-for="(item, index) in floors"
:key="index"
class="floor"
:ref="el => { floorRefs[index] = el }"
>
<h2>{{ item.name }}</h2>
<!-- 楼层具体内容 -->
</div>
</div>
</template>
核心逻辑实现
- 数据与引用初始化
import { ref, onMounted, onUnmounted } from 'vue';
const floors = ref([ { name: '家电', top: 0 }, { name: '服饰', top: 0 }, // 更多楼层... ]); const currentFloor = ref(0); const floorRefs = ref([]);
2. 滚动监听与位置计算
```javascript
const handleScroll = () => {
const scrollY = window.scrollY;
floors.value.forEach((floor, index) => {
const el = floorRefs.value[index];
if (el) {
const rect = el.getBoundingClientRect();
floors.value[index].top = rect.top + scrollY;
}
});
// 判断当前所在楼层
for (let i = floors.value.length - 1; i >= 0; i--) {
if (scrollY >= floors.value[i].top - 100) { // 100为偏移阈值
currentFloor.value = i;
break;
}
}
};
onMounted(() => {
window.addEventListener('scroll', handleScroll);
// 初始化计算各楼层位置
setTimeout(handleScroll, 50); // 等待DOM渲染
});
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll);
});
- 点击导航跳转
const scrollTo = (index) => { currentFloor.value = index; window.scrollTo({ top: floors.value[index].top, behavior: 'smooth' }); };
CSS关键样式
.nav {
position: fixed;
right: 20px;
top: 50%;
transform: translateY(-50%);
}
.nav div {
padding: 10px;
cursor: pointer;
}
.nav div.active {
color: #f10215; /* 京东红 */
font-weight: bold;
}
.floor {
min-height: 100vh;
padding: 20px;
}
性能优化建议
-
使用
throttle限制滚动事件频率:import { throttle } from 'lodash-es'; const throttledScroll = throttle(handleScroll, 100); window.addEventListener('scroll', throttledScroll); -
对于复杂楼层内容,使用
IntersectionObserver替代滚动监听:const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const index = floorRefs.value.findIndex(el => el === entry.target); if (index !== -1) currentFloor.value = index; } }); }, { threshold: 0.5 });
onMounted(() => { floorRefs.value.forEach(el => observer.observe(el)); });
---
### 完整示例扩展
如需实现京东首页的复杂楼层效果(如吸顶时切换导航栏),可结合Vue的`v-if`和CSS的`position: sticky`:
```html
<div class="sticky-nav" v-if="isSticky">
<!-- 吸顶后的简化导航 -->
</div>
通过计算scrollY与目标位置的关系控制isSticky的布尔值。






