实现效果如上图所示。
首先引入better-scroll的组件:
1、npm安装better-scroll插件。
npm install--save better-scroll
2、在文件中引入better-scroll。
import BScroll from 'better-scroll';
排序使用的是pinyin的包,将字符串转成拼音,就可以通过字符串截取取出拼音首字母,这样就可以进行首字母排序了。
1、安装方式:
npm install pinyin
2、在应用的.vue文件中单独引入
var pinyin = require("pinyin");
准备工作结束,现在开始正式编写页面:
<template>
<div id="Container" style="min-height: 100%">
<van-sticky>
<searchbox />
</van-sticky>
<van-row class="main" style="display: flex">
<div class="bar">
<sidebar> </sidebar>
</div>
<van-row class="listzhanwei" style="margin-top: 0.5rem">
<div class="scrollFather" ref="listView">
<ul class="brandlist">
<div
class="rowclass"
v-for="(group, k) in searchlist"
:key="k"
ref="listGroup"
>
<van-row>
<div class="first">
{{ group.first }}
</div>
</van-row>
<van-row>
<van-col span="12" v-for="(item, i) in group.value" :key="i">
</van-col>
</van-row>
</div>
<div class="zhanwei" style="height: 3.2rem"></div>
</ul>
</div>
</van-row>
</van-row>
<div class="list-shortcut" ref="firstList">
<ul>
<li
ref="firstItem"
v-for="(item, index) in shortcutList"
class="item"
:data-index="index"
:key="index"
@click="scrollToIndex"
>
{{ item }}
</li>
</ul>
</div>
</div>
</template>
样式也附送一下:
<style >
body {
margin: 0;
padding: 0;
}
.scrollFather {
/* overflow-y: scroll; */
overflow: hidden;
position: absolute;
height: 100%;
width: 83%;
}
.first {
font-weight: bold;
line-height: 0.7rem;
background-color: #ffffff;
font-size: 0.6rem;
/* margin-top: 0.5rem; */
margin-bottom: 0.6rem;
margin-left: 0.5rem;
display: flex;
justify-content: flex-start;
}
.list-shortcut {
position: fixed;
z-index: 30;
right: 0.2rem;
color: black;
top: 50%;
transform: translateY(-50%);
text-align: center;
background: #fff;
/* user-select: none; */
cursor: pointer;
}
.list-shortcut .item {
line-height: 0.8rem;
color: #8a8a8f;
font-size: 0.7rem;
}
</style>
接下来是功能实现。
<script>
import pinyin from "pinyin";
// 导入列表接口
import Better from "better-scroll";
export default {
components: {
sidebar: sidebar,
searchbox: searchbox,
},
data() {
return {
searchlist: [],
//滚动条
shortcutList: [],
};
},
created() {
this.getInfo();
},
computed: {},
watch: {},
methods: {
async getInfo() {
let brandJson = {};
//获取自己的信息列表
const res = await getInfoList();
console.log(res);
for (let i = 0; i < res.data.length; i++) {
//遍历数组,拿到品牌名称
let brandName = res.data[i].brand;
//取全部品牌的首字母,这里截取首字母的第一位且大写
let fristName = pinyin(brandName, {
style: pinyin.STYLE_NORMAL,
heteronym: true,
})[0][0]
.substring(0, 1)
.toUpperCase();
//给原json添加首字母键值对
res.data[i].first = fristName;
if (!brandJson[fristName]) {
this.shortcutList.push(fristName);
brandJson[fristName] = {
first: fristName,
value: [],
};
}
brandJson[fristName].value.push(res.data[i]);
}
// 转为数组
var ret = [];
for (var k in brandJson) {
var val = brandJson[k];
ret.push(val);
}
// 对首字母排序
ret.sort((a, b) => {
return a.first.charCodeAt(0) - b.first.charCodeAt(0);
});
this.shortcutList.sort((a, b) => {
return a.charCodeAt(0) - b.charCodeAt(0);
});
// 对每个品牌进行排序
ret.map((v) => {
v.value.sort((a, b) => {
return a["brand"].localeCompare(b["brand"]);
});
});
this.searchlist = ret;
},
scrollToIndex(e) {
console.log(this.$refs.listGroup);
let index = this.shortcutList.indexOf(e.target.innerText);
this.$nextTick(() => {
this.scroll.scrollToElement(this.$refs.listGroup[index]);
if (index == this.$refs.listGroup.length - 1) {
this.scroll.scrollBy(0, -100);
}
});
},
},
mounted() {
setTimeout(() => {
this.scroll = new Better(this.$refs.listView, {
probeType: 3,
click: true,
});
this.scroll.refresh();
}, 200);
},
</script>
但是以上方法会有一个问题,字母侧边导航栏只能展示已有数据的存在的首字母,是根据自己的数据定的,不一定是26个字母全有。想要另外导入26个字母可以使用:
const letterlist = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
但是当点击列表中没有的字母时,页面不会有任何变化且后台会报错。想到一个迂回的方法,也就是当点击的字母是不存在的首字母项时,检查前一位字母是否存在对应的信息,依此类推。修改后的代码(只贴出修改的部分):
导航条的输出:
<div class="list-shortcut" ref="firstList">
<ul>
<li
ref="firstItem"
v-for="(item, index) in shortcutList"
class="item"
:data-index="index"
:key="index"
@click="scrollToIndex(item.index)"
>
{{ item.value }}
</li>
</ul>
</div>
JS:
data() {
return {
searchlist: [],
//滚动条
shortcutList: {},
hascutList: [],
};
},
methods: {
async getInfo() {
//获取自己的信息列表
const sampleres = await getInfo();
const brandList = sampleres.result.data;
let brandJson = {};
const letterlist = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
for (let i = 0; i < brandList.length; i++) {
//遍历数组,拿到列表项的名称
let brandName = brandList[i].c_name;
//取全部的首字母,这里截取首字母的第一位且大写
let fristName = pinyin(brandName, {
style: pinyin.STYLE_NORMAL,
heteronym: true,
})[0][0]
.substring(0, 1)
.toUpperCase();
//给原json添加首字母键值对
brandList[i].first = fristName;
if (!brandJson[fristName]) {
this.hascutList.push(fristName);
brandJson[fristName] = {
first: fristName,
value: [],
};
}
brandJson[fristName].value.push(brandList[i]);
}
// 转为数组
var ret = [];
for (var k in brandJson) {
var val = brandJson[k];
ret.push(val);
}
// 对首字母排序
ret.sort((a, b) => {
return a.first.charCodeAt(0) - b.first.charCodeAt(0);
});
this.hascutList.sort((a, b) => {
return a.charCodeAt(0) - b.charCodeAt(0);
});
// 对每个信息项进行排序
ret.map((v) => {
v.value.sort((a, b) => {
return a["c_name"].localeCompare(b["c_name"]);
});
});
//初始化字母导航条所有的项,加入index字段
letterlist.forEach((e, index) => {
this.shortcutList[index] = {
index: index,
value: e,
};
});
//遍历26个字母
letterlist.forEach((e, k) => {
//如果列表分类后首字母存在,则把first的index赋值给导航条中的字母项,这个必须在前
if (this.hascutList.indexOf(e) >= 0) {
this.hascutList.forEach((ele, index) => {
if (ele === e) {
this.shortcutList[k] = {
index: index,
value: e,
};
return;
}
});
} else {
//如果列表分类后首字母不存在,则把前一项存在的字母的index赋值给当前的字母项
if (this.hascutList.indexOf(e) < 0) {
// console.log(letterlist[k]);
for (let i = 1; i < 26; i++) {
if (this.hascutList.indexOf(letterlist[k - i]) >= 0) {
// console.log(i + "_" + this.shortcutList[k - i].value);
this.shortcutList[k] = {
index: this.shortcutList[k - i].index,
value: e,
};
return;
}
}
}
}
});
this.searchlist = ret;
},
//滚动条跳转
scrollToIndex(e) {
let index = e;
this.$nextTick(() => {
this.scroll.scrollToElement(this.$refs.listGroup[index]);
if (index == this.$refs.listGroup.length - 1) {
this.scroll.scrollBy(0, -100);
}
});
},
},
其实是比较笨的方法,如果有更简单的方法欢迎分享~