<template><!-- Vue模板部分 --><div><div v-for="(group, index) in groupedArray" :key="index" ref="indexcatch"><h2>{{ letter[index] }}</h2><ul><li v-for="item in group" :key="item.id">{{ item.name }}</li></ul></div><div ref="scrollDiv"style="position: fixed;right: 0;top: calc(50vh - 325px);width: 50px; height: 650px;background-color: #CCCCCC;"@click="handleClick" @mousedown="startLongPress" @mouseup="stopLongPress"><div v-for="(item,index) in letter" :key="index":style="{textAlign: 'center',height: '25px',color:IndexItem==index?'red':'black',fontWeight:IndexItem==index?'700':''}">{{letter[index]}}</div></div></div>
</template><script>// yarn add js-pinyin --save 或者 npm install js-pinyin --save 安装// 作用是把汉字转化为拼音,以便于排序使用import Pinyin from 'js-pinyin'; export default {data() {return {letter: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S','T', 'U', 'V', 'W', 'X', 'Y', 'Z'], // 右侧字母列表arr: [], // 被处理过的左侧数据列表数据(已经分类好)EleHeight: 25, // 右侧每个字母的高(使用这个高度用于计算点击的或者滚动到的是哪个索引的字母,以便于让左侧列表跟着进行滚动到指定位置)FatherDivHeight: -1, // 右侧字母列表的容器距离浏览器顶部的距离IndexItem: -1, // 用于将字母高亮显示};},computed: {groupedArray() {let result = {};// 生成随机名字的函数(这个是找GPT要的方法,你也用不上,毕竟你的项目是有数据的,这里是模拟的数据,就不写注释了)function getRandomName() {const surnames = ['张', '王', '李', '赵', '刘', '陈', '杨', '黄', '吴', '郑', '孙', '周', '徐', '朱', '高', '林', '何','马', '罗', '梁', '宋', '郭', '胡', '郭', '潘', '李', '谢', '邓', '曹', '程', '曾', '彭', '蔡', '梁', '田', '许','韩', '冯', '曹', '庄', '魏', '张', '石', '章', '叶', '董', '汪', '方', '于', '邹', '苏', '潘', '葛', '奚', '范','彭', '郎', '鲁', '韦', '昌', '马', '苗', '凤', '花', '贾', '严', '武', '庄', '邱', '卫', '蒋', '童', '颜', '郭','梅', '盛', '林', '翟', '石', '王'];const names = ['三', '四', '五', '六', '七', '八', '九', '十', '一', '二', '华', '明', '强', '超', '辉', '军', '涛','勇', '毅', '伟', '刚', '强', '军', '平', '杰', '峰', '雷', '磊', '新', '洋', '宇', '昊', '翔', '晓', '亮', '云','飞', '鹏', '浩', '波', '文', '轩', '东', '俊', '涵', '阳', '晨', '帆', '宇', '航', '建', '琪', '轩', '海', '立','智', '志', '弘', '博', '晨', '瑞', '凯', '子', '卓', '坤', '雄', '霖', '政', '晗', '煜', '�'];let getRandomItem = (arr) => arr[Math.floor(Math.random() * arr.length)];let randomNames = [];for (let i = 0; i < 299; i++) {let surname = getRandomItem(surnames);let name = getRandomItem(names);randomNames.push({"name": surname + name});}return randomNames;}this.arr = getRandomName();this.arr.forEach(item => {let firstLetter = this.getFirstLetter(item.name);if (!result[firstLetter]) {result[firstLetter] = [];}result[firstLetter].push(item);});let allLetters = 'abcdefghijklmnopqrstuvwxyz'.split('');let groupedArray = allLetters.map(letter => result[letter] || []);return groupedArray;}},methods: {getFirstLetter(str) {// 将中文姓名转换为拼音并取首字母return Pinyin.getCamelChars(str).charAt(0).toLowerCase();},startLongPress(e) {// 鼠标按下(开始监听全局的鼠标滚动)this.FatherDivHeight = e.currentTarget.offsetTop // 获取当前字母容器距离顶部的距离// 添加全局事件监听器document.addEventListener('mousemove', this.handleScroll);},stopLongPress() {// 移除全局事件监听器(鼠标抬起移除全局的鼠标移动事件)document.removeEventListener('mousemove', this.handleScroll);},handleClick(event) {// 点击滚动实现// 获取当前滚动的y坐标// console.log(event.y);// 获取当前字母列表每个字母的高度// console.log(this.EleHeight);// 计算当前字母索引let index = Math.ceil((event.detail.y - this.FatherDivHeight) / this.EleHeight) - 1;console.log(index);// 将当前索引赋值this.IndexItem = index// 将右侧列表滚动到相应位置scrollTo({left: 0, // 距离左侧距离top: this.$refs.indexcatch[index].offsetTop, //点击侧边栏的哪个索引就让右侧哪个索引对应的块滚动behavior: "smooth", // 点击滚动这里我用了平滑滚动,带动画的})},handleScroll(event) {// 获取当前滚动的y坐标// console.log(event.y);// 获取当前字母列表每个字母的高度// console.log(this.EleHeight);// 计算当前字母索引let index = Math.ceil((event.y - this.FatherDivHeight) / this.EleHeight) - 1;console.log(index);// 将当前字母索引赋值this.IndexItem = index// 将右侧列表滚动到相应位置scrollTo({left: 0,top: this.$refs.indexcatch[index].offsetTop, //点击侧边栏的哪个索引就让右侧哪个索引对应的块滚动behavior: "auto", // auto 瞬间滚动 无动画 smooth 平滑滚动带有动画效果})}}};
</script>
效果图
支持滑动和点击