列表滚动选择与点击选择居中展示
核心需求描述 有一个边框高度为200,其中有30个列表竖着展示,边框是可以滚动的,每次滚动选中一个列表内容并添加一个class,滚动的时候内容一直是居中展示 列表也是可以点击选中
<!DOCTYPE html> <html> <head> <style> .container { height: 200px; overflow: hidden; border: 1px solid #ccc; position: relative; } .list { list-style: none; padding: 0; margin: 0; position: absolute; top: 0; left: 0; width: 100%; transition: transform 0.2s ease; } .list-item { height: 40px; line-height: 40px; text-align: center; cursor: pointer; /* 鼠标悬浮指针 */ } .list-item.active { background: #007bff; color: white; } </style> </head> <body> <div class="container" id="container"> <ul class="list" id="list"> <!-- 30个列表项 --> <li class="list-item">项1</li> <li class="list-item">项2</li> <li class="list-item">项3</li> <li class="list-item">项4</li> <li class="list-item">项5</li> <li class="list-item">项6</li> <li class="list-item">项7</li> <li class="list-item">项8</li> <li class="list-item">项9</li> <li class="list-item">项10</li> <li class="list-item">项11</li> <li class="list-item">项12</li> <li class="list-item">项13</li> <li class="list-item">项14</li> <li class="list-item">项15</li> <li class="list-item">项16</li> <li class="list-item">项17</li> <li class="list-item">项18</li> <li class="list-item">项19</li> <li class="list-item">项20</li> <li class="list-item">项21</li> <li class="list-item">项22</li> <li class="list-item">项23</li> <li class="list-item">项24</li> <li class="list-item">项25</li> <li class="list-item">项26</li> <li class="list-item">项27</li> <li class="list-item">项28</li> <li class="list-item">项29</li> <li class="list-item">项30</li> </ul> </div> <script> const container = document.getElementById('container'); const list = document.getElementById('list'); const items = document.querySelectorAll('.list-item'); const itemHeight = 40; const containerCenter = container.clientHeight / 2; let currentIndex = 0; // 初始化选中第一个 items[currentIndex].classList.add('active'); // 核心滚动/选中逻辑 const scrollToIndex = (index) => { currentIndex = Math.max(0, Math.min(index, items.length - 1)); const translateY = containerCenter - (itemHeight * currentIndex + itemHeight / 2); list.style.transform = `translateY(${translateY}px)`; items.forEach((item, i) => item.classList.toggle('active', i === currentIndex)); }; // 滚轮事件 container.addEventListener('wheel', (e) => { e.preventDefault(); scrollToIndex(currentIndex + (e.deltaY > 0 ? 1 : -1)); }); // 点击事件 items.forEach((item, i) => { item.addEventListener('click', () => scrollToIndex(i)); }); </script> </body> </html>
效果图


改成vue3
<template> <div class="container" ref="containerRef" @wheel="handleWheel"> <ul class="list" :style="{ transform: `translateY(${translateY}px)` }"> <li v-for="(item, index) in 30" :key="index" class="list-item" :class="{ active: currentIndex === index }" @click="scrollToIndex(index)" > 项{{ index + 1 }} </li> </ul> </div> </template> <script setup> import { ref, computed, onMounted } from 'vue'; // 响应式数据 const currentIndex = ref(0); const containerRef = ref(null); // 容器DOM引用 const itemHeight = 40; // 列表项高度固定 // 计算容器中心位置(挂载后获取DOM尺寸) const containerCenter = ref(0); // 计算列表偏移量(响应式) const translateY = computed(() => { return containerCenter.value - (itemHeight * currentIndex.value + itemHeight / 2); }); // 核心滚动/选中逻辑 const scrollToIndex = (index) => { currentIndex.value = Math.max(0, Math.min(index, 29)); // 30项索引0-29 }; // 滚轮事件处理 const handleWheel = (e) => { e.preventDefault(); scrollToIndex(currentIndex.value + (e.deltaY > 0 ? 1 : -1)); }; // 组件挂载后获取容器尺寸 onMounted(() => { if (containerRef.value) { containerCenter.value = containerRef.value.clientHeight / 2; } }); </script> <style scoped> .container { height: 200px; overflow: hidden; border: 1px solid #ccc; position: relative; } .list { list-style: none; padding: 0; margin: 0; position: absolute; top: 0; left: 0; width: 100%; transition: transform 0.2s ease; } .list-item { height: 40px; line-height: 40px; text-align: center; cursor: pointer; } .list-item.active { background: #007bff; color: white; } </style>

浙公网安备 33010602011771号