Skip to content

Instantly share code, notes, and snippets.

@zymiboxpay
Last active November 18, 2016 08:45
Show Gist options
  • Save zymiboxpay/4d2cfa78e213aa5665e721cf033da589 to your computer and use it in GitHub Desktop.
Save zymiboxpay/4d2cfa78e213aa5665e721cf033da589 to your computer and use it in GitHub Desktop.
javascript 通讯录 索引 效果与微信类似

目标

  • 用javascript实现一个与微信通讯录效果相似的插件

要求

  • 易用
  • 尽量遵守 weui 设计规范
  • 最好是原生的,不依赖 jQuery
  • 页面滚动要流畅

分阶段目标

  • 正确分类数据
  • 点击索引跳转
  • 顶栏显示
  • 滚动流畅不卡
  • 搜索联系人
  • 对输入数据排序

license

MIT license

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name=”viewport” content=”initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0″>
<title>Contacts</title>
<style>
.page {
height: 10000px;
}
.shortcuts_ctn {
position: fixed;
top: 50%;
transform: translateY(-50%);
right: 0;
width: 20px;
display: flex;
flex-direction: column;
text-align: center;
}
.list {
position: relative;
padding: 0px;
list-style-type: none;
}
.list li {
height: 40px;
line-height: 40px;
padding-left: 10px;
border-top: 1px solid #eee;
}
.list li[id*=hook] {
height: 20px;
line-height: 20px;
background-color: #eee;
border-top: none;
}
.list li[id*=hook] + li {
border-top: none;
}
.list li.on_top {
position: fixed;
top: 0;
width: 100%;
}
</style>
</head>
<body>
<div class="page">
</div>
<script>
var raw_data = ['banana','cat','egg','farmer','food','jeep','joke','lisa','low','jude','apple',1,'2','谭小生', '张中','李大哥'];
var dict_map = parseData(raw_data);
generate_shortcuts(dict_map);
var list = generate_list(dict_map);
var ctn = generate_ctn_input();
ctn.appendChild(list);
document.querySelector('.page').appendChild(ctn);
function generate_shortcuts(map){
var items = [];
for(var key in map) {
if( map.hasOwnProperty( key ) && (map[key].length != 0)) {
items.push(key);
}
}
var ctn = document.createElement('div');
ctn.classList.add('shortcuts_ctn');
items.forEach(function(item){
var text = document.createTextNode(item);
var a = document.createElement('a');
a.setAttribute('href', '#hook_' + item);
a.setAttribute('rel', 'internal');
a.appendChild(text);
ctn.appendChild(a);
});
document.body.appendChild(ctn);
}
function generate_list(map){
var former_key = null;
var list = document.createElement('ul');
list.classList.add('list');
for(var key in map) {
if( map.hasOwnProperty( key ) && (map[key].length != 0)) {
var items = map[key];
items.forEach(function(item){
var text,li;
if(key != former_key){
text = document.createTextNode(key);
li = document.createElement('li');
li.classList.add('hooks');
li.setAttribute('id', 'hook_' + key);
li.appendChild(text);
list.appendChild(li);
former_key = key;
}
text = document.createTextNode(item);
li = document.createElement('li');
li.appendChild(text);
list.appendChild(li);
});
}
}
return list;
}
function generate_ctn_input(){
var ctn = document.createElement('div');
ctn.classList.add('container');
var input = document.createElement('input');
input.classList.add('search');
ctn.appendChild(input);
return ctn;
}
function parseData(data){
var map = {};
var c = 'A'.charCodeAt();
for(; c <= 'Z'.charCodeAt(); c++ ){
map[String.fromCharCode(c)] = [];
}
map['#'] = [];
var first_char_upper;
data.forEach(function(item){
first_char_upper = getFirstUpperChar(item);
if (map.hasOwnProperty(first_char_upper)) {
map[first_char_upper].push(item);
} else {
map['#'].push(item);
}
});
return map;
}
function getFirstUpperChar(str){
string = String(str);
var c = string[0];
if (/[^\u4e00-\u9fa5]/.test(c)) {
return c.toUpperCase();
}
else {
return chineseToEnglish(c);
}
}
// copy from https://ruby-china.org/topics/29026
function chineseToEnglish(c){
var idx = -1;
var MAP = 'ABCDEFGHJKLMNOPQRSTWXYZ';
var boundaryChar = '驁簿錯鵽樲鰒餜靃攟鬠纙鞪黁漚曝裠鶸蜶籜鶩鑂韻糳';
if (!String.prototype.localeCompare) {
throw Error('String.prototype.localeCompare not supported.');
}
if (/[^\u4e00-\u9fa5]/.test(c)) {
return c;
}
for (var i = 0; i < boundaryChar.length; i++) {
if (boundaryChar[i].localeCompare(c, 'zh-CN-u-co-pinyin') >= 0) {
idx = i;
break;
}
}
return MAP[idx];
}
// get positions
var positions = [];
function getAllAnchorPositions(){
var anchors = document.querySelectorAll('.hooks');
anchors = [].slice.call(anchors);
anchors.forEach(function(anchor){
positions.push({
anchor: anchor,
pos: anchor.offsetTop
});
});
}
getAllAnchorPositions();
// get positions
function getTopbarElement(scroll_position){
var i = 0;
while((i < positions.length - 1) && scroll_position > positions[i].pos){
i ++;
}
var index = Math.min(Math.max(0, i-1), positions.length - 1 );
return positions[index].anchor;
}
// scroll optimization
// see https://developer.mozilla.org/en-US/docs/Web/Events/scroll
var last_known_scroll_position = 0;
var ticking = false;
var top_bar_element = null;
window.addEventListener('scroll', function(e){
last_known_scroll_position = window.scrollY;
if(!ticking) {
window.requestAnimationFrame(function(){
//do some thing here
positions.forEach(function(item){
item.anchor.classList.remove('on_top');
});
top_bar_element = getTopbarElement(last_known_scroll_position);
top_bar_element.classList.add('on_top');
ticking = false;
});
}
ticking = true;
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment