vue实现index list
Vue 实现 Index List(索引列表)
基础实现思路
使用 Vue 的 v-for 指令结合计算属性对数据进行分组,通过监听滚动事件实现高亮索引联动。核心步骤包括数据分组、渲染列表、添加右侧索引栏及滚动交互。
数据分组处理
假设原始数据为城市列表,按首字母分组:
computed: {
groupedData() {
const groups = {};
this.listData.forEach(item => {
const firstChar = item.name.charAt(0).toUpperCase();
if (!groups[firstChar]) {
groups[firstChar] = [];
}
groups[firstChar].push(item);
});
return Object.entries(groups).sort((a, b) => a[0].localeCompare(b[0]));
}
}
模板结构
<div class="index-list">
<!-- 主列表 -->
<div class="list-container" ref="list" @scroll="handleScroll">
<div v-for="([letter, items], index) in groupedData" :key="letter" :data-letter="letter">
<h3 class="list-header">{{ letter }}</h3>
<div class="list-item" v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</div>
</div>
<!-- 右侧索引栏 -->
<div class="index-bar">
<div
v-for="([letter]) in groupedData"
:key="letter"
@click="scrollTo(letter)"
:class="{ active: activeIndex === letter }"
>
{{ letter }}
</div>
</div>
</div>
滚动联动实现
methods: {
scrollTo(letter) {
const target = this.$refs.list.querySelector(`[data-letter="${letter}"]`);
if (target) {
this.$refs.list.scrollTo({
top: target.offsetTop,
behavior: 'smooth'
});
}
},
handleScroll() {
const letters = this.groupedData.map(([letter]) => letter);
const scrollTop = this.$refs.list.scrollTop;
const listItems = this.$refs.list.querySelectorAll('[data-letter]');
for (let i = 0; i < listItems.length; i++) {
const item = listItems[i];
const nextItem = listItems[i + 1];
if (
scrollTop >= item.offsetTop - 10 &&
(!nextItem || scrollTop < nextItem.offsetTop - 10)
) {
this.activeIndex = item.dataset.letter;
break;
}
}
}
}
样式优化建议
.index-list {
display: flex;
height: 100vh;
}
.list-container {
flex: 1;
overflow-y: auto;
}
.list-header {
padding: 10px;
background: #f5f5f5;
position: sticky;
top: 0;
}
.index-bar {
width: 20px;
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
}
.index-bar div {
padding: 2px 0;
cursor: pointer;
}
.index-bar div.active {
color: #42b983;
font-weight: bold;
}
性能优化方案
对于大数据量场景,可采用虚拟滚动技术。推荐使用第三方库如 vue-virtual-scroller:
import { RecycleScroller } from 'vue-virtual-scroller';
// 模板中替换列表部分
<RecycleScroller
class="scroller"
:items="flattenedData"
:item-size="50"
key-field="id"
v-slot="{ item }"
>
<div v-if="item.isHeader" class="list-header">
{{ item.letter }}
</div>
<div v-else class="list-item">
{{ item.name }}
</div>
</RecycleScroller>
完整组件封装建议
可将索引列表封装为可复用组件,通过 props 接收数据源:

props: {
data: {
type: Array,
required: true,
validator: value => value.every(item => 'name' in item)
},
keyField: {
type: String,
default: 'id'
}
}






