在做移动端开发时,有时需要用到类似于下图所示的场景,一个城市列表的页面滚动效果,或者是类似的页面效果。为了实现更好的用户体验,用户在向下滚动时,将相应的顶部字母标题固定在页面上部是很炫酷的。
如何实现呢,主要的思路是运用 better-scroll 实时监听页面的滚动坐标,当 Y 轴坐标变化时,计算当前Y轴的坐标所在的字母区间。举个例子,假如 B 字母区间底端距离页面顶端的高度为 300px,C 字母区间的底端距离页面顶端的高度为 400px,那么当Y轴坐标为 360px 时,顶部字母标题应该取值为 B 。依次类推,其实也并不复杂。
下面我们来逐步实现。
1.计算每组城市区间高度
需要用到的变量:
cityHeightList: [], // 城市区间列表列表高度
_caclHeight() { // 当前城市 + 热门城市高度 let height = this.$refs.locCityRef.clientHeight + this.$refs.hotCityRef.clientHeight; this.cityHeightList.push(height); let cityGroup = this.$refs.cityGroupRef; for (let item of cityGroup) { height += item.clientHeight; this.cityHeightList.push(height); } },
this.$refs.locCityRef 为当前城市 div。this.$refs.hotCityRef 为热门城市 div。
this.$refs.cityGroupRef 为每组城市的 div 集合,以 A 开头的城市一个 div,以 B 开头的城市一个 div...,将所有的 div 通过 v-for 循环出来。
2.在 template 中引用 better-scroll 组件:
<b-scroll class="content-scroll" v-show="!cityKeyword" ref="cityScrollRef" :listenScroll="listenScroll" :probeType="probeType" v-on:scroll="cityScroll" > ... </b-scroll>
注: probeType 的值只有设置成 2 或者 3 ,better-scroll 才会实时监听滚动位置。
v-on:scroll = "cityScroll" 为监听子组件的事件:
2.1 better-scroll 组件,通过 this.$emit 将 scroll 事件派发出来,pos 为滚动的实时位置:
//实时监听滚动事件 || 监听better-scroll滚动事件 if(this.listenScroll) { let _this = this; // pos 滚动的实时坐标 {x, y} this.scroll.on('scroll', pos => { // 向父组件派发滚动事件 _this.$emit('scroll', pos) }); }
2.2 监听子组件派发的 scroll 事件 | 实时获取滚动的 Y 坐标
cityScroll(pos) { this.scrollY = pos.y; },
2.3 父组件监听 scrollY 的变化
用到的变量 :
topFixedTitle: '', // 顶部固定字母标题 letterList: [], //城市名称中包含的大写首字母
Y 轴的实时位置与城市字母区间高度对比,找到当前顶部固定字母标题的取值。
watch: { scrollY(newY) { (newY > 0 || -newY < this.cityHeightList[0]) && (this.topFixedTitle = ''); for (let i=0; i<this.cityHeightList.length; i++) { let height_1 = this.cityHeightList[i]; let height_2 = this.cityHeightList[i+1]; if(-newY > height_1 && -newY <= height_2) { this.topFixedTitle = this.letterList[i]; } } }, }
注意:子组件传递过来的沿 Y 轴向下滑动的位置值是负的,因此我们用 -newY 取正值后与高度进行比较。
3.顶部固定字母标题,在 template 中添加:
<!-- 固定顶部字母标题 --> <article class="fixed-top" v-show="topFixedTitle && !isSearchCity" ref="topTitleRef"> {{ topFixedTitle }} </article>
CSS:
.fixed-top { position: absolute; top: 0; left: 0; width: 100%; background: #f2f2f2; height: 8vw; line-height: 8vw; padding-left: 2.5vw; }
到这里我们就完成啦。如果文章中有不正确的地方,欢迎大家留言指正。
创作不易,若文章帮助到了大家,大家可以点击右下角的打赏按钮,请笔者喝咖啡哦。O(∩_∩)O