最近公司需求要做一个字母导航联系人列表,自己有一些思路解决这个问题。由于以前没有写过,在做这个需求前,想看看别人都是怎么解决的,于是在网上搜索了一番,找到了一篇文章《一步一步实现字母索引导航栏》来实现这个需求。以下作者都是指该篇文章作者,该篇文章链接见文尾。
作者写的非常详细,作者用了纯js实现,不依赖任何三方库。作者采用了订阅--发布的设计模式来实现了这个功能。作者使用设计模式的思想很不错,并且提供了扩展的能力。但是对于我们的实际需求可能不用做的这么麻烦。总结几点如下:
1、这种功能一般只有移动端有,pc端几乎没见过,所以不必考虑pc端的兼容
2、这个功能可扩展性不是很强,而且每个公司ui都是不同的,都要自己实现,变动大点基本要重写。所以没有必要搞个设计模式出来实现这个简单功能。
3、现在为了提高开发效率,做前端用纯js写代码的应该不多了。前端比较火的框架和库就是react、vue、angular所 以我想结合框架来实现这一功能。
于是自己动手实现了一番,本demo用react、vue两个版本来实现,不要问我为什么不用angular来实现,是不是鄙视angular?那就冤枉啊,因为我压根就不会angular。
效果图:
因为是移动端:
1、我用了flex布局解决了右边字母纵向布局,简化了作者用js动态计算距离的过程。
2、通过监听原生的touchstart、touchmove、touchend事件获取当前点到顶部的距离,在根据整个字符串所占的高度可以计算出当前点所处的字符串是什么。
getChar (clientY) {
const charHeight = this.$refs.charBar.offsetHeight / this.charList.length;// 计算没一个字符高度
const index = Math.floor((clientY - this.boxClientTop) / charHeight); // 获取当前触点是第几个字符串减一
return this.charList[index]; // 取出当前触摸的字符串
}
3、通过右边监听的字符串的变化来执行左边列表定位。左边列表在渲染时,每个字母首次渲染时,在前面插入一个标记。在通过scrollIntoView这个属性来定位。
gotoChar (char) {
if (char === this.lastChar) { // 上一次触发的字符串储存起来,如果此次触发字符串与上次相同,则不执行以下逻辑
return false;
}
this.lastChar = char; // 否则将本次字符串赋值给上一次字符串
if (char === '*') { // 对于特殊字符串处理,如收藏的数据可以用 * 表示
this.$refs.countryList.scrollTop = 0;
} else if (char === '#') { // 不属于26个字母里的数据可以放在这里如联系人为数字开头的
this.$refs.countryList.scrollTop = this.$refs.countryList.scrollHeight;
}
const target = document.querySelector('[data-en="' + char + '"]');
if (target) {
target.scrollIntoView();
}
}
本项目的webpack配置不是实际项目中的配置,只是方便查看效果而建的简单的项目,本项目数据来自源作者的项目。
git clone https://github.com/keenjaan/alphabetical-index-navigation.git
npm i
npm run vue // 查看vue版本效果
npm run react // 查看react版本效果