Vue + better-scroll 实现顶部固定字母标题

在做移动端开发时,有时需要用到类似于下图所示的场景,一个城市列表的页面滚动效果,或者是类似的页面效果。为了实现更好的用户体验,用户在向下滚动时,将相应的顶部字母标题固定在页面上部是很炫酷的。

如何实现呢,主要的思路是运用 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

 

 

 

posted @ 2020-08-19 10:19  几行  阅读(637)  评论(0编辑  收藏  举报