TabControl中包含三个表示分类的tag:流行(pop)、新款(new)和精选(sell)。当点击对应的tag后,下方显示的商品列表便会进行相应的切换。此外,TabControl组件还有一个重要的功能就是:当向下滚动到一定距离后,它会悬停在滚动区域的顶部。下面我们来依次实现这些功能。
关于TabControl的外观结构,其实和之前总结的“Detail中的NavBar”很相似,都是遍历父组件传入的数组显示tag标签,并且同时给每个tag绑定事件监听,在事件监听函数中让currentIndex等于被点击tag的index。如果检测到currentIndex等于某个tag的index,则为其绑定新的高亮样式。为了切换下方显示的商品列表,这里将单击事件、以及被点击tag的索引发送给了父组件。
<template> <div class="tab-control"> <div v-for="(item, index) in titles" :key="index" class="tab-control-item" :class="{active: index === currentIndex}" @click="itemClick(index)"> <span>{{item}}</span> </div> </div> </template>
itemClick(index){
this.currentIndex = index
this.$emit(‘tabClick‘, index)
}
TabControl在父组件中的使用:
<tab-control :titles="[‘流行‘, ‘新款‘, ‘精选‘]" @tabClick="tabClick" ref="tabControl2"></tab-control>
商品列表是Home父组件的另一个子组件:GoodsList,它通过currentType属性来切换显示的商品类型,所以父组件的单击处理函数可以如下实现:
tabClick(index) { switch (index) { case 0: this.currentType = "pop"; break; case 1: this.currentType = "new"; break; case 2: this.currentType = "sell"; } }
这样切换商品列表的目的我们就达到了,下面讨论如何让他吸顶。
什么时候吸顶呢?答案是当tabControl组件滚到滚动视口的顶部时,换句话说,就是当滚动的距离刚好等于tabControl组件上方内容的高度时。而tabControl上方的高度在轮播图图片加载完成后就可以获取了,这个时候我们在轮播图组件中传出的swiperImageLoad事件就派上用场了,tabControl上方的高度可以通过其根标签($el)的offsetTop属性来获取,使用tabOffsetTop变量来存储:
swiperImageLoad() { this.tabOffsetTop = this.$refs.tabControl2.$el.offsetTop; }
当页面滚动时,会触发scrollEvent方法,我们可以在该方法内部判断滚动的距离是否等于tabControl上方的高度:
scrollEvent(position) { this.tabFixed = (-position.y > this.tabOffsetTop) }
综上所述,当tabFixed等于true时,tabControl就可以吸顶了。接下来我们采用一种比较hack的方法来完成吸顶操作。
具体来说,就是复制一份tabControl组件,将它放在滚动区域的外面,即让它和scroll组件同一级别。默认情况下该复制品是隐藏的,而只有当需要吸顶时它才显示。这样相当于滚动到页面下方时,当前页面中同时存在两个tabControl,只不过在滚动区域内的那一份因为超出了视口区域的范围所以不可见。具体结构如下:
<tab-control :titles="[‘流行‘, ‘新款‘, ‘精选‘]" @tabClick="tabClick" ref="tabControl1" v-show="tabFixed" class="tabControl"></tab-control> <scroll class="content" ref="scroll" :probe-type="3" @scroll="scrollEvent" :pull-up-load="true" @pullingUp="loadMore"> ...... <tab-control :titles="[‘流行‘, ‘新款‘, ‘精选‘]" @tabClick="tabClick" ref="tabControl2"></tab-control> <goods-list :goods="showGoods"></goods-list> </scroll>
我们可以设置不同的ref来区分这两个tabControl。将用来吸顶的那个记作tabControl1,一开始就显示的那个记作tabControl2。注意我们前面获取高度时使用的应该是tabControl2。
此时,问题看似解决了,实际上还存在一个小bug:当切换一个tabControl中的tag时,另一个不会做出相应的改变。比如我让tabControl2切换到“精选”,然后下拉超过一定距离后发生吸顶,此时我看到的其实是tabControl1,而它此时高亮显示的还是默认的“流行”。这个Bug也很好解决,因为我们无论点击哪个tabControl,都会触发Home组件中的tabClick函数,并且传入被点击tag的index,所以只需要在该函数中修改另一个tabControl的currentIndex即可,如下:
this.$refs.tabControl1.currentIndex = index
this.$refs.tabControl2.currentIndex = index