vue单页应用中实现仿微信通信录选择功能
基础滚动:better-scroll https://github.com/ustbhuangyi/better-scroll一名讲晒,万变不离其宗。。。核心是window.scroll事件,获取到当前滚动y轴的scrollTop,初始化列表数据项的clientHeight,每项基于前一项增加,监听scrollY,如果满足clientHeightArray范围(可用for循环或者递归),即可取..
·
基础滚动:better-scroll https://github.com/ustbhuangyi/better-scroll
一名讲晒,万变不离其宗。。。
核心是window.scroll事件,获取到当前滚动y轴的scrollTop,初始化列表数据项的clientHeight,每项基于前一项增加,监听scrollY,如果满足clientHeightArray范围(可用for循环或者递归),即可取出当前索引index,然后执行对应跳转逻辑,说这么多废话,还是上代码吧。。。
<template>
<div class="p-repay_banklist" ref="list">
<div class="p-repay--banklist" ref="listView">
<ul ref="ul">
<li v-for="group in formatBankList" class="p-banklist--item" :key="group.initial" ref="listGroup">
<div class="bank-item-header txt-color--6 txt-size--28">{{ group.initial }}</div>
<ul class="bank-item-content">
<li @click="selectBank(item,$event)" v-for="item in group.cells" class="o-repay_cell o-repay_cell--bdb o-repay_cell--p30 txt-size--32" :key="item.id">
<span class="bank-icon">
<img :src="item.param2" style="max-width:100%;height:auto;"/>
</span>
<span>{{item.name}}</span>
</li>
</ul>
</li>
</ul>
<div class="list-shortcut p-banklist--guide">
<ul>
<li v-for="(item, index) in quickguideList"
class="txt-size--32 txt-color--2"
:data-index="index"
:key="item.id"
@touchstart.prevent="onShortcutStart"
@touchmove.stop.prevent="onShortcutMove"
@touchend.stop.prevent="onShortcutEnd"
:class="{'current': currentIndex === index}"
>
{{ item }}
<span>{{item}}</span>
</li>
</ul>
</div>
<div class="index-list-fixed txt-color--9 txt-size--28" ref="fixed" v-show="fixedTitle">
{{fixedTitle}}
</div>
</div>
</div>
</template>
<script>
import BScroll from "better-scroll";
const TITLE_HEIGHT = 30;
export default {
data() {
return {
scrollY: 0,
currentIndex: null,
bankList: [],
formatBankList: [],
quickguideList: []
};
},
computed: {
fixedTitle() {
if (this.scrollY > TITLE_HEIGHT) {
return "";
}
return this.quickguideList[this.currentIndex]
? this.quickguideList[this.currentIndex]
: "";
}
},
watch: {
scrollY(newVal) {
// 向下滑动的时候 newVal 是一个负数,所以当 newVal > 0 时,currentIndex 直接为 0
if (newVal > 0) {
this.currentIndex = 0;
return;
}
// 计算 currentIndex 的值
var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
var scrollHeight = this.$refs.ul.scrollHeight;
//有滚动条的时候,当滚动距离在listheight范围内
for (var i = 0; i < this.listHeight.length - 1; i++) {
var height1 = this.listHeight[i];
var height2 = this.listHeight[i + 1];
if (-newVal >= height1 && -newVal < height2 && (-newVal + windowHeight) < scrollHeight ) {
this.currentIndex = i;
return;
}
}
}
},
methods: {
selectBank(item,e) {
if(!e._constructed) {
return
}
this.$cookies.set('bankName',item.name)
this.$router.push(this.$store.state.wantTo)
},
singleUnique(arr) {
//数组过滤相同的单个元素
var hash = [];
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
++i;
}
}
hash.push(arr[i]);
}
return hash;
//var x = new Set(arr);return [...x];
},
unique(arr, name) {
//数组过滤相同的对象
// var result = [];
// var obj = {};
// for(var i =0; i<arr.length; i++){
// if(!obj[arr[i].name]){
// result.push(arr[i]);
// obj[arr[i].name] = true;
// }
// }
// return result
let hash = {};
return arr.reduce(function(item, next) {
hash[next[name]] ? "" : (hash[next[name]] = true && item.push(next));
return item;
}, []);
},
_initSrcoll() {
this.scroll = new BScroll(this.$refs.listView, {
probeType: 3,
click: true
});
this.scroll.on("scroll", pos => {
this.scrollY = pos.y;
});
},
onShortcutStart(e) {
e.target.children[0].classList.add('active')
// 获取到绑定的 index
let index = e.target.getAttribute("data-index");
let firstTouch = e.touches[0].pageY;
this.touch.y1 = firstTouch;
this.touch.anchorIndex = index;
this.scrollToElement(index);
},
onShortcutMove(e) {
e.target.children[0].classList.add('active')
// 再记录一下移动时候的 Y坐标,然后计算出移动了几个索引
let touchMove = e.touches[0].pageY;
this.touch.y2 = touchMove;
// 这里的 16.7 是索引元素的高度
let delta = Math.floor((this.touch.y2 - this.touch.y1) / 16.7);
// 计算最后的位置
// * 1 是因为 this.touch.anchorIndex 是字符串,用 * 1 偷懒的转化一下
let index = this.touch.anchorIndex * 1 + delta;
this.scrollToElement(index);
},
onShortcutEnd(e) {
e.target.children[0].classList.remove('active')
},
scrollToElement(index) {
// console.log(index)
// 处理边界情况
// 因为 index 通过滑动距离计算出来的
// 所以向上滑超过索引框框的时候就会 < 0,向上就会超过最大值
var windowHeight = document.documentElement.clientHeight || document.body.clientHeight
var scrollHeight = this.$refs.ul.scrollHeight
if(index < 0) {
return
}
let curVal = this.listHeight[index]
let curIndex = index
if(this.listHeight[index] + windowHeight >= scrollHeight) {
for(var i = 0; i < this.listHeight.length; i++) {
if(this.listHeight[i] + windowHeight >= scrollHeight) {
curIndex = i - 1
break
}
}
}
// listHeight 是正的, 所以加个 -
this.scrollY = -this.listHeight[curIndex]
this.scroll.scrollToElement(this.$refs.listGroup[curIndex]);
},
_calculateHeight() {
this.listHeight = [];
let list = this.$refs.listGroup;
let height = 0;
this.listHeight.push(height);
for (let i = 0; i < list.length - 1; i++) {
let item = list[i];
height += item.clientHeight;
this.listHeight.push(height);
}
}
},
created() {
this.commonApi.getParams({ typeId: "11" }).then(res => {
if (res.returnCode == 0) {
res.data.forEach(item => {
this.bankList.push(item.currentNode);
this.bankList = this.unique(this.bankList, "name");
});
this.bankList.forEach(item => {
item.py = item.py.substr(0, 1).toUpperCase();
this.quickguideList.push(item.py);
this.quickguideList = this.singleUnique(this.quickguideList).sort();
});
this.quickguideList.forEach(item => {
this.formatBankList.push(
this.arrDataFormat(this.bankList, item, "py")
);
});
// setTimeout(() => {
// this._initSrcoll()
// this._calculateHeight()
// },20)
this.$nextTick(() => {
this._initSrcoll();
this._calculateHeight();
});
}
});
},
mounted() {
this.touch = {};
}
};
</script>
<style lang="scss">
@import "~@sass/_variables";
@import "~@sass/_func";
.p-repay_banklist {
.p-repay--banklist {
width: 100%;
height: 100%;
}
}
.p-banklist--item {
display: flex;
flex-direction: column;
.o-repay_cell {
display: flex;
justify-content: flex-start;
}
.bank-item-header {
height: 0.6rem;
line-height: 0.7rem;
margin: 0 0.4rem;
}
.bank-item-content {
background: $bg-white;
padding: 0 0.4rem;
.bank-icon {
display: inline-block;
width: 0.586667rem;
height: 0.586667rem;
overflow: hidden;
margin-right: 0.266667rem;
}
}
}
.p-banklist--guide {
position: fixed;
right: 0rem;
top: 10%;
padding: 0.2rem 0.35rem;
background: transparent;
li {
list-style: none;
margin-bottom: 0.1rem;
position: relative;
span {
display: none;
position: absolute;
top:0;
left: -0.45rem;
&.active{
display: block;
}
}
&.current {
color: red;
position: relative;
}
}
}
.index-list-fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
padding-left: 0.4rem;
width: 100%;
height: 0.64rem;
line-height: 0.64rem;
color:red;
background: #f2f2f2;
}
</style>
把代码放出来,主要是在网上搜索的案例基本都是用本地数据模拟的,不太符合实战,还是得自己动手,丰衣足食。。。
更多推荐
已为社区贡献3条内容
所有评论(0)