做项目的时候要用到手机联系人列表的功能,没弄过,找了几仿的效果也并不是很好,没有原版手机联系人效果不能滑动不能顶部顶上去,想想用别人的代码,还不如自己写着痛快。想着就从QQ音乐的数据抓去歌手数据排行。我们常见的手机联系人信息是按字母顺序排列的列表,通过点击右侧的字母,会迅速定位检索到首字母对应的联系人,还可以根据右侧字母滑动检测到左边的首字母联系人,在向上滑动时可以明显观察到左侧字母向上顶的效果。综上那么多,这次就是来做这个列表吧
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="reset.css">
<title>Document</title>
<style>
.listView{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
background: #222
}
.listView .list-group{
padding-bottom: 30px
}
.listView .list-group .list-group-title{
height: 30px;
line-height: 30px;
padding-left: 20px;
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
background: #333;
}
.listView .list-group .list-group-item{
display: flex;
align-items: center;
padding: 20px 0 0 30px;
}
.listView .list-group .list-group-item .avatar{
width: 50px;
height: 50px;
border-radius: 50%;
}
.listView .list-group .list-group-item .name{
margin-left: 20px;
color: rgba(255, 255, 255, 0.5);
font-size: 14px;
}
.listView .list-shortcut{
position: absolute;
z-index: 30;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 20px;
padding: 20px 0;
border-radius: 10px;
text-align: center;
background: rgba(0, 0, 0, 0.3);
font-family: Helvetica;
}
.listView .list-shortcut .item{
padding: 3px;
line-height: 1;
color: rgba(255, 255, 255, 0.5);
font-size: 12px;
}
.listView .list-shortcut .item.current{
color: #ffcd32
}
.listView .list-fixed{
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.listView .list-fixed .fixed-title{
height: 30px;
line-height: 30px;
padding-left: 20px;
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
background: #333;
}
</style>
</head>
<body>
<div class="listView" id="listView">
<ul id="listWrapper"></ul>
<script id="listWrapperBox" type="text/doTtemplate">
{{for(var i in it) {}}
<li class="list-group">
<h2 class="list-group-title">{{=it[i].title}}</h2>
<ul>
{{for(var j in it[i].items) {}}
<li class="list-group-item">
<img src="{{=it[i].items[j].avatar}}" class="avatar">
<span class="name">{{=it[i].items[j].name}}</span>
</li>
{{ } }}
</ul>
</li>
{{ } }}
</script>
<div class="list-shortcut" id="list-shortcut">
<ul id="shortcutWrapper"></ul>
<script id="shortcutWrapperBox" type="text/doTtemplate">
{{for(var i in it) {}}
<li class="item" data-index="{{=[i]}}">{{=it[i].title.substr(0, 1)}}</li>
{{ } }}
</script>
</div>
<div class="list-fixed" id="list-fixed">
<h1 class="fixed-title" id="fixed-title"></h1>
</div>
</div>
<script src="bscroll.js"></script>
<script src="jquery-3.1.1.min.js"></script>
<script src="doT.min.js"></script>
<script>
// 定义一个常量
var HOT_NAME = '热门';
var HOT_LEN = 10;
// 定义全局 touch 来共享 touchstart 和 touchmove 的 pageY 值和 anchorIndex
var touch = {};
// 定义每个 shortcut 的高度
var ANCHOR_HEIGHT= 18;
// 滚动的高度和单个区间距离顶部的适口的高度差
var diff = -1;
// list-fixed 高度
var TITLE_HEIGHT = 30;
// 文档初始化
$( document ).ready( readyHandler );
// 请求列表数据
function readyHandler() {
$.post( "data.json", null, loadHandler, "json" );
}
/**
* 1. 数据列表加载完成
* @param data
*
* 2. mock QQ音乐的数据,抓过来的数据不是想要的数据,没有改,只能手动更改自己想要的数据结构
* 最后拿到用的数据是 dataList
* 可以打印看下 dataList 内的数据格式和最初的数据 data 比较
*/
function loadHandler( data ) {
//console.log( data );
var list = data.list;
var map = {
hot: {
title: HOT_NAME,
items: []
}
};
data.list.forEach(function (item, index) {
// 判断是否索引是否小于 10条,就添加到热门数据内
if (index < HOT_LEN) {
map.hot.items.push({
id: item.Fsinger_mid,
name: item.Fsinger_name,
avatar : 'https://y.gtimg.cn/music/photo_new/T001R150x150M000'+ item.Fsinger_mid +'.jpg?max_age=2592000'
})
}
// 根据Findex 做一个聚类,判断map 数组内是否有key,没有就赋值
var key = item.Findex;
if( !map[key] ){
map[key] = {
title: key,
items: []
}
}
map[key].items.push({
id: item.Fsinger_mid,
name: item.Fsinger_name,
avatar : 'https://y.gtimg.cn/music/photo_new/T001R150x150M000'+ item.Fsinger_mid +'.jpg?max_age=2592000'
})
});
var hot = [];
var ret = [];
for(var key in map){
var val = map[key];
// 正则校验 检测从字母 a 到 z,逐个添加到 ret 数组内
if(val.title.match(/[a-zA-Z]/)){
ret.push(val)
// 如果title 是 热门,就添加到 hot 数组内
}else if(val.title === HOT_NAME){
hot.push(val)
}
}
// 数组 ret 的排序,如果相减大于 0 就为 true,这样就可以拿到 a到z 的顺序
ret.sort(function(a, b) {
return a.title.charCodeAt(0) - b.title.charCodeAt(0)
});
// 合并的数组就是有序排列数据,可以用作循环遍历
var dataList = hot.concat(ret);
setDataList(dataList)
}
function setDataList(dataList) {
console.log(dataList);
/*
* 1. 先填充数据,然后再判断 listWrapper 是否有内容,有内容就实例 BScroll
* 2. 监听右侧 list-short 的touchstart 事件,点击跳到左侧对应的列表页
* 3. 通过全局存储的 y2 和 y1相减,来确定 touchmove 在 list-shortcut 的移动的距离
* 4. 通过BScroll 提供的方法 scrollToElement 滚动到相应的位置
* 5. 滚动监测右侧shortcut 联动效果
* 6. 设置滚动文字顶上,通过控制 dom 的偏移来做效果
*/
var listWrapperBoxTpl,shortcutWrapperBoxTpl,listView;
listWrapperBoxTpl = doT.template(document.getElementById('listWrapperBox').innerHTML);
document.getElementById("listWrapper").innerHTML = listWrapperBoxTpl(dataList);
shortcutWrapperBoxTpl = doT.template(document.getElementById('shortcutWrapperBox').innerHTML);
document.getElementById("shortcutWrapper").innerHTML = shortcutWrapperBoxTpl(dataList);
if($("#listWrapper").html()) {
listView = new BScroll(document.getElementById('listView'), {
probeType: 3
});
$("#fixed-title").html('热门');
}
document.getElementById("list-shortcut").addEventListener('touchstart', function (e) {
//console.log(e);
$(e.target).addClass("current").siblings().removeClass("current");
var anchorIndex = e.target.attributes[1].value;
// 给touch 添加一个 y1 属性
var firstTouch = e.touches[0];
touch.y1 = firstTouch.pageY;
touch.anchorIndex = anchorIndex;
listView.scrollToElement(document.getElementsByClassName("list-group")[anchorIndex], 0)
});
document.getElementById("list-shortcut").addEventListener('touchmove', function (e) {
// 阻止浏览器的默认行为
e.preventDefault;
// 给touch 添加一个 y2 属性
var firstTouch = e.touches[0];
touch.y2 = firstTouch.pageY;
// 除以 18 再向下取整
var delta = (touch.y2 - touch.y1) / ANCHOR_HEIGHT | 0;
// 拿到上面的 anchorIndex 是个字符串
var anchorIndex = parseInt(touch.anchorIndex) + delta;
listView.scrollToElement(document.getElementsByClassName("list-group")[anchorIndex], 0);
$(document.getElementsByClassName("item")[anchorIndex]).addClass("current").siblings().removeClass("current");
});
var listGroup = document.getElementsByClassName("list-group");
var height = 0;
var listHeight = [];
listHeight.push(height);
for (var i = 0; i < listGroup.length; i++) {
var item = listGroup[i];
height += item.clientHeight;
listHeight.push(height);
}
listView.on('scroll', function (pos) {
// 获取滚动的高度,默认的向下滚动是 负值
var upScrollY = Math.round(pos.y);
// 获取滚动的高度,加绝对值
var scrollY = Math.abs(Math.round(pos.y));
for(var i = 0; i < listHeight.length; i++){
var height1 = listHeight[i];
var height2 = listHeight[i + 1];
if ((scrollY >= height1 && scrollY < height2)) {
// 高度差
diff = height2 - scrollY;
$($(".item")[i]).addClass("current").siblings().removeClass("current");
// 判断如果是向下拖拽滚动,就隐藏 list-fixed
if(upScrollY < 0){
// 通过滚动添加文字
$("#fixed-title").html(dataList[i].title);
$("#list-fixed").css("display", "block")
}else {
$("#list-fixed").css("display", "none")
}
}
}
// console.log(diff);
/*
* 设置 list-fixed 的属性改变位置来做顶部向上偏移
*/
var fixedTop = (diff > 0 && diff < TITLE_HEIGHT) ? diff - TITLE_HEIGHT : 0;
document.getElementById('list-fixed').style.transform = 'translate3d(0,'+ fixedTop +'px,0)'
});
// 给第一个添加默认点击
$("#shortcutWrapper").children().first().addClass("current")
}
</script>
</body>
</html>
猛戳这里: 快速预览