![cover](https://img-blog.csdnimg.cn/956c213d35d9465d99bb32867047eb52.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8yOTQ5MTg4NQ==,size_16,color_FFFFFF,t_70)
vue/js 实现仿通讯录-列表滑动字母索引
最近写东西刚好遇到如下设计:要求实现地区按字母排序加上侧边索引点击侧边索引滑动到指定字母列表页面滑动的时候顶栏序列号随之变化PC端鼠标悬浮,移动端触屏侧边索引实现以上两个效果步骤从country.json获取countryList数据提取侧边栏字母并排序将countryList按照字母分类排序对侧边栏进行操作不废话直接上代码代码有一丢丢长,如果看不下去可以直接 ...
·
最近写东西刚好遇到如下设计:
要求
- 实现地区按字母排序
- 加上侧边索引
- 点击侧边索引滑动到指定字母列表
- 页面滑动的时候顶栏序列号随之变化
- PC端鼠标悬浮,移动端触屏侧边索引实现以上两个效果
步骤
- 从country.json获取countryList数据
- 提取侧边栏字母并排序
- 将countryList按照字母分类排序
- 对侧边栏进行操作
不废话直接上代码
代码有一丢丢长,如果看不下去可以直接 点击下载源码查看调试
注意:下载源码后
不要直接双击
打开index.html,用本地的 http://localhost 或 http://127.0.0.1/ 方式打开
<article class="country" ref="listview" v-show="countryList.length>0" v-cloak @scroll="setScrollY">
<ul class="country-list">
<li v-for="group in countryList" ref="listGroup">
<h2 class="list-group-title">{{group.title}}</h2>
<ul>
<li v-for="item in group.items" :class="[{active:phoneCode==item.code},'list-group-item']" @click="phoneCode=item.code">
<span class="name">{{lang=='cn'?item.name_cn:item.name_en}}</span>
<span>(+{{item.code}})</span>
</li>
</ul>
</li>
</ul>
<ul class="list-shortcut" @click.stop.prevent="onShortcutTouchStart" @touchstart="onShortcutTouchStart" @touchmove.stop.prevent="onShortcutTouchMove" @touchend.stop.prevent="onShortcutTouchEnd">
<li @mouseover.stop.prevent="onMouseover(index)" @mouseout.stop.prevent="onShortcutTouchEnd" :class="[{selected:fixedTitle==item},'item']" v-for="(item,index) in shortcut">{{item}}</li>
</ul>
<div class="selected-shortcut" v-show="isTouch">{{fixedTitle}}</div>
<div class="list-fixed" v-show="fixedTitle" ref="fixed">{{fixedTitle}}</div>
</article>
<script src="./js/jquery-3.2.1.js"></script>
<script src="./js/vue.js"></script>
<script src="./js/pinyin_dict_notone.js"></script>
<script src="./js/pinyinUtil.js"></script>
<script type="text/javascript">
$(function() {
new Vue({
el: ".country",
data: {
isTouch:false,
countryList: [],
shortcut: [],
phoneCode: '93',
touch: {},
listHeight: [],
scrollY: -1,
currentIndex: 0,
diff: -1,
fixedTop: -1,
lang:'cn',
},
created() {
// 根据浏览器语言判断中文还是英文
var navLanguage = (navigator.browserLanguage || navigator.language).toLowerCase().slice(0,2);
if(navLanguage=='zh'){
this.lang='cn'
}else{
this.lang='en';
}
// 获取国家列表
this.getCountryList();
},
computed: {
fixedTitle() {
return this.shortcut[this.currentIndex] ? this.shortcut[this.currentIndex] : 'A'
}
},
mounted() {
setTimeout(()=>{
this.calculateTotalHeight()
}, 200)
},
methods: {
setScrollY(){
this.scrollY = $('.country').scrollTop()
},
getCountryList() {
$.getJSON('./js/country.json', (res)=>{
// 格式化数据
var map = {};
var sortKey = this.lang == "cn" ? "name_cn" : "name_en";
res.forEach((item, index) => {
// 中文按照拼音首字母进行筛选分组,英文根据单词首字母分组
var key = this.lang=='cn'?pinyinUtil.getPinyin(item[sortKey]).slice(0, 1).toUpperCase():item[sortKey].slice(0,1);
if (!map[key]) {
this.shortcut.push(key)
map[key] = {
title: key,
items: []
}
}
map[key].items.push(item);
})
// 转为数组
var ret = [];
for (var k in map) {
var val = map[k];
ret.push(val);
}
// 对首字母排序
ret.sort((a, b)=>{
return a.title.charCodeAt(0) - b.title.charCodeAt(0);
});
this.shortcut.sort((a, b) =>{
return a.charCodeAt(0) - b.charCodeAt(0);
});
// 对每个国家进行排序
ret.map(v => {
v.items.sort((a, b) => {
return a[sortKey].localeCompare(b[sortKey]);
});
});
this.countryList = ret;
})
},
onShortcutTouchStart(e) {
let anchorIndex = this.shortcut.indexOf(e.target.innerText);
this.touch.y1 = e.pageY ? e.pageY : e.touches[0].pageY
this.touch.anchorIndex = anchorIndex;
this.scrollToIndex(anchorIndex);
this.isTouch = true;
},
onShortcutTouchMove(e) {
this.touch.y2 = e.touches[0].pageY
var delta = (this.touch.y2 - this.touch.y1) / 16 | 0
var anchorIndex = parseInt(this.touch.anchorIndex) + parseInt(delta)
this.scrollToIndex(anchorIndex);
this.isTouch = true;
},
onShortcutTouchEnd(){
this.isTouch = false;
},
onMouseover(index){
this.touch.anchorIndex = index;
this.scrollToIndex(index);
this.isTouch = true;
},
scrollToIndex(index) {
this.$refs.listview.scrollTo(0, this.listHeight[index])
},
calculateTotalHeight() {
var list = this.$refs.listGroup
var height = 0
this.listHeight.push(height)
if(list&&list.length>0){
for (var i = 0; i < list.length; i++) {
var item = list[i]
height += item.clientHeight
this.listHeight.push(height)
}
}
}
},
watch: {
scrollY(newY) {
var listHeight = this.listHeight
// 当滚动到顶部时, newY<=0
if (newY <= 0) {
this.currentIndex = 0
return
}
// 中间部分滚动
for (var i = 0; i < listHeight.length - 1; i++) {
var height1 = listHeight[i]
var height2 = listHeight[i + 1]
if (!height2 || (newY >= height1 && newY < height2)) {
this.currentIndex = i
this.diff = height2 - newY
return
}
}
// 滚动到底部且newY大于最后一个元素的上限
this.currentIndex = listHeight.length - 1
},
diff(newVal) {
var fixedTop = (newVal - 24) < 0 ? newVal - 24 : 0
if (this.fixedTop === fixedTop) {
return false;
}
this.fixedTop = fixedTop
this.$refs.fixed.style.transform = `translate3d(-50%,${fixedTop}px,0)`
}
}
})
})
</script>
我的个人博客,有空来坐坐
更多推荐
所有评论(0)