标签栏实现功能:
- 页面向下滑动,标签栏吸顶。
- 点击标签项,标签项呈现选中态,并切换到对应的面板。
- 在面板中进行滑动,可切换标签项和面板。
<!-- tabs.wxml -->
<wxs module="touch" src="./touch.wxs"></wxs>
<view class="tabs">
<view class="tab-navs">
<view class="tab-nav" wx:for="{{tabs}}" wx:key="index">
<!-- 通过对比 index 与当前点击的标签项的下标来实现选中态 -->
<view class="tab-label {{currentTabIndex === index ? 'active-tab-label' : ''}}" data-index="{{index}}" bindtap="handleTabChange">{{item}}</view>
<view class="tab-divider" wx:if="{{currentTabIndex === index}}"></view>
</view>
</view>
<!-- 滑动切换面板 -->
<view class="tab-panel" bindtouchstart="{{touch.handleTouchstart}}" bindtouchend="{{touch.handleTouchend}}"></view>
</view>
// tabs.js
Page({
data: {
tabs: ['全部', '待付款', '待发货', '待收货', '售后'],
currentTabIndex: 0, // 记录当前点击的标签项的下标
},
// 点击标签项切换到对应的面板
// 快速点击标签项,可能会导致面板中渲染出来的请求数据错乱。原因是:事件和网络请求都是异步的,快速触发事件无法保证它的执行顺序和触发顺序一致,而且,也无法保证网络请求返回数据的顺序和触发顺序一致。因此使用节流函数防止频繁触发调用(节流函数此处不做具体实现,可查看事件稀释一文)。
handleTabChange: throttle(function(e) {
const {index} = e.target.dataset
const {currentTabIndex} = this.data
if (index === currentTabIndex) return
this.setData({currentTabIndex: index})
}, 500),
// 逻辑层和视图层的通信以及页面的重新渲染,性能开销极大。因此,不直接在 js 中监听滑动事件,而是使用 WXS 函数用来响应小程序事件,让事件在视图层响应,从而减少通信的次数和页面的重新渲染达到性能的优化。
// 根据滑动方向切换面板
handleTouch(values) {
const {direction} = values
const {tabs, currentTabIndex} = this.data
const target = currentTabIndex + direction
// 越界判断
if (target < 0 || target > tabs.length - 1) return
this.setData({currentTabIndex: target})
}
})
// touch.wxs
var touchStart
function handleTouchstart(e) {
// 记录触摸开始的 X 轴的位置
touchStart = e.changedTouches[0].clientX
}
function handleTouchend(e) {
// 记录触摸结束的 X 轴的位置
var touchEnd = e.changedTouches[0].clientX
// 负数表示手指向左滑动,正数表示手指向右滑动
var distance = touchEnd - touchStart
// 定义滑动方向。-1:页面后退(向右滑动);0:不动;1:页面前进(向左滑动)
var direction = 0
// 设置一个阈值,超出才切换面板
var threshold = 30
if (distance < -threshold) {
direction = 1
} else if (distance > threshold) {
direction = -1
}
if (direction !== 0) {
// 调用引用该 wxs 的组件的方法,传递滑动方向
e.instance.callMethod('handleTouch', {direction: direction})
}
}
module.exports = {
handleTouchstart: handleTouchstart,
handleTouchend: handleTouchend,
}
/* tabs.wxss */
.tabs {
width: 100%;
// 不能设置父元素的 height 为 100%,否则当页面滑动到一定高度之后 sticky 属性会失效。标签项不再吸顶被顶走。
// 原因:和粘性定位的原理有关,在实现吸附效果时,会根据父元素的大小来进行定位。如果设置父元素高度为 100%,那么就会按照这个高度来定位,但是页面中的数据是分页加载的,父元素的高度会越来越高,那么初始计算出的定位就是错误的。
// 解决方法:设置 min-height
min-height: 100%;
display: flex;
flex-direction: column;
}
.tab-navs {
display: flex;
// 设置粘性定位
position: sticky;
top: 0;
z-index: 99999;
}
.tab-nav {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 0;
}
.tab-label {
color: #333333;
white-space: nowrap;
}
.active-tab-label {
color: #FF4A2F;
}
.tab-divider {
width: 40rpx;
height: 5rpx;
background-color: #FF4A2F;
margin-top: 10rpx;
}
.tab-panel {
flex: 1;
}