最近公司需求要做一個字母導(dǎo)航聯(lián)系人列表,自己有一些思路解決這個問題。由于以前沒有寫過,在做這個需求前,想看看別人都是怎么解決的,于是在網(wǎng)上搜索了一番,找到了一篇文章《一步一步實現(xiàn)字母索引導(dǎo)航欄》來實現(xiàn)這個需求。以下作者都是指該篇文章作者,該篇文章鏈接見文尾。
作者寫的非常詳細(xì),作者用了純js實現(xiàn),不依賴任何三方庫。作者采用了訂閱--發(fā)布的設(shè)計模式來實現(xiàn)了這個功能。作者使用設(shè)計模式的思想很不錯,并且提供了擴(kuò)展的能力。但是對于我們的實際需求可能不用做的這么麻煩??偨Y(jié)幾點如下:
1、這種功能一般只有移動端有,pc端幾乎沒見過,所以不必考慮pc端的兼容
2、這個功能可擴(kuò)展性不是很強(qiáng),而且每個公司ui都是不同的,都要自己實現(xiàn),變動大點基本要重寫。所以沒有必要搞個設(shè)計模式出來實現(xiàn)這個簡單功能。
3、現(xiàn)在為了提高開發(fā)效率,做前端用純js寫代碼的應(yīng)該不多了。前端比較火的框架和庫就是react、vue、angular所 以我想結(jié)合框架來實現(xiàn)這一功能。
于是自己動手實現(xiàn)了一番,本demo用react、vue兩個版本來實現(xiàn),不要問我為什么不用angular來實現(xiàn),是不是鄙視angular?那就冤枉啊,因為我壓根就不會angular。
效果圖:

1.gif
因為是移動端:
1、我用了flex布局解決了右邊字母縱向布局,簡化了作者用js動態(tài)計算距離的過程。
2、通過監(jiān)聽原生的touchstart、touchmove、touchend事件獲取當(dāng)前點到頂部的距離,在根據(jù)整個字符串所占的高度可以計算出當(dāng)前點所處的字符串是什么。
getChar (clientY) {
const charHeight = this.$refs.charBar.offsetHeight / this.charList.length;// 計算沒一個字符高度
const index = Math.floor((clientY - this.boxClientTop) / charHeight); // 獲取當(dāng)前觸點是第幾個字符串減一
return this.charList[index]; // 取出當(dāng)前觸摸的字符串
}
3、通過右邊監(jiān)聽的字符串的變化來執(zhí)行左邊列表定位。左邊列表在渲染時,每個字母首次渲染時,在前面插入一個標(biāo)記。在通過scrollIntoView這個屬性來定位。
gotoChar (char) {
if (char === this.lastChar) { // 上一次觸發(fā)的字符串儲存起來,如果此次觸發(fā)字符串與上次相同,則不執(zhí)行以下邏輯
return false;
}
this.lastChar = char; // 否則將本次字符串賦值給上一次字符串
if (char === '*') { // 對于特殊字符串處理,如收藏的數(shù)據(jù)可以用 * 表示
this.$refs.countryList.scrollTop = 0;
} else if (char === '#') { // 不屬于26個字母里的數(shù)據(jù)可以放在這里如聯(lián)系人為數(shù)字開頭的
this.$refs.countryList.scrollTop = this.$refs.countryList.scrollHeight;
}
const target = document.querySelector('[data-en="' + char + '"]');
if (target) {
target.scrollIntoView();
}
}
本項目的webpack配置不是實際項目中的配置,只是方便查看效果而建的簡單的項目,本項目數(shù)據(jù)來自源作者的項目。
git clone https://github.com/keenjaan/alphabetical-index-navigation.git
npm i
npm run vue // 查看vue版本效果
npm run react // 查看react版本效果