<template>
<view class="container">
<!-- 左侧地区列表 -->
<scroll-view
class="left-list"
scroll-y
:scroll-into-view="currentLetterId"
scroll-with-animation
@scroll="onScroll"
ref="scrollView"
>
<view
v-for="group in dataList"
:key="group.letter"
:id="'letter-' + group.letter"
class="group"
:data-letter="group.letter"
>
<view class="group-letter">{{ group.letter }}</view>
<view style="display: flex; gap: 20rpx; padding: 20rpx;">
<view v-for="item in group.items" :key="item" class="item">{{ item }}</view>
</view>
</view>
</scroll-view>
<!-- 右侧字母索引 -->
<view
class="right-index"
@touchstart.prevent="onTouchStart"
@touchmove.prevent="onTouchMove"
@touchend.prevent="onTouchEnd"
ref="indexWrapper"
>
<view
v-for="(letter, index) in letters"
:key="letter"
class="letter"
:class="{ active: letter === activeLetter }"
:data-index="index"
>
{{ letter }}
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
letters: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
dataList: [
{ letter: 'A', items: ['安庆', '鞍山', '安阳'] },
{ letter: 'B', items: ['北京', '保定', '包头'] },
{ letter: 'C', items: ['长沙', '成都', '重庆'] },
{ letter: 'D', items: ['大连', '东莞', '德阳'] },
{ letter: 'F', items: ['福州', '佛山'] },
{ letter: 'G', items: ['广州', '贵阳'] },
{ letter: 'H', items: ['杭州', '合肥', '哈尔滨'] },
{ letter: 'J', items: ['济南', '嘉兴'] },
{ letter: 'K', items: ['昆明'] },
{ letter: 'L', items: ['兰州', '洛阳'] },
{ letter: 'M', items: ['绵阳'] },
{ letter: 'N', items: ['南京', '南昌'] },
{ letter: 'Q', items: ['青岛', '泉州'] },
{ letter: 'S', items: ['上海', '苏州', '深圳'] },
{ letter: 'T', items: ['天津', '唐山'] },
{ letter: 'W', items: ['武汉', '无锡'] },
{ letter: 'X', items: ['厦门', '西安'] },
{ letter: 'Y', items: ['烟台', '宜昌'] },
{ letter: 'Z', items: ['郑州', '珠海'] }
],
currentLetterId: '',
activeLetter: '',
indexItemHeight: 0,
indexTop: 0,
};
},
mounted() {
// 获取右侧字母索引容器的位置和单个字母高度
uni.createSelectorQuery()
.select('.right-index')
.boundingClientRect(rect => {
console.log('打印高度')
console.log(rect)
this.indexTop = rect.top;
})
.exec();
// 获取每个字母的高度
this.$nextTick(() => {
const letterHeights = [];
this.letters.forEach((letter, index) => {
uni.createSelectorQuery()
.select(`.right-index .letter:nth-child(${index + 1})`)
.boundingClientRect(rect => {
letterHeights.push(rect.height);
// 当所有字母的高度都获取到后,计算平均高度
if (letterHeights.length === this.letters.length) {
this.indexItemHeight = letterHeights.reduce((a, b) => a + b, 0) / letterHeights.length;
console.log('字母高度')
console.log(this.indexItemHeight)
}
})
.exec();
});
});
},
methods: {
scrollToLetter(letter) {
this.currentLetterId = 'letter-' + letter;
this.activeLetter = letter;
},
onTouchStart(e) {
this.handleTouch(e);
},
onTouchMove(e) {
this.handleTouch(e);
},
onTouchEnd() {
// 触摸结束可以做一些清理操作,如果需要
},
handleTouch(e) {
const touch = e.touches[0];
const y = touch.clientY;
// 计算触摸点相对于字母索引顶部的偏移
let index = Math.floor((y - this.indexTop) / this.indexItemHeight);
if (index < 0) index = 0;
if (index >= this.letters.length) index = this.letters.length - 1;
const letter = this.letters[index];
if (letter && letter !== this.activeLetter) {
this.scrollToLetter(letter);
}
},
onScroll(e) {
// 可选:根据滚动位置动态改变右侧高亮字母
// 这里可以实现滚动联动右侧字母高亮,稍复杂,可根据需求添加
}
}
};
</script>
<style>
.container {
display: flex;
height: 100vh;
background-color: #fff;
}
.left-list {
flex: 1;
}
.group {
padding: 20rpx 0;
}
.group-letter {
font-weight: bold;
font-size: 36rpx;
background: #F2F4F5;
padding: 10rpx 30rpx;
}
.item {
width: 120rpx;
height: 42rpx;
line-height: 42rpx;
background-color: #F2F4F5;
text-align: center;
border-radius: 30rpx;
font-size: 24rpx;
}
.right-index {
width: 60rpx;
background: transparent;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
user-select: none;
/* 方便触摸 */
padding: 10rpx 0;
}
.letter {
font-size: 28rpx;
color: #666;
padding: 4rpx 0;
width: 100%;
text-align: center;
cursor: pointer;
}
.letter.active {
color: #007AFF;
font-weight: bold;
}
/* 通用隐藏方案 */
::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
/* 安卓专用优化 */
/* #ifdef APP-PLUS */
scroll-view ::-webkit-scrollbar {
display: none;
}
/* #endif */
</style>
最后效果,可以根据需要调试