终于入坑小程序了,最近开发小程序,要实现一个tab切换效果,看到知乎热榜上的滑动切换tab效果还挺舒服的,刚好项目也需要这个功能,就尝试实现一下,首先需要一些基本知识点
循环渲染数据
小程序有类似vue的写法,但是还有区别的
data: {
arr: [1,2,3]
}
<view wx:for="{{arr}}">{{item}}</view>
wx:for-item
默认情况下遍历的每一项用item来获取,如果要指定item的名称,可以用wx:for-item
<view wx:for="{{arr}}" wx:for-item="i">{{i}}</view>
wx:key
同vue一样,设置一个key属性可以优化列表渲染,微信也可以设置一个key,如果数组是每一项是唯一的字符串或者数字,可以使用wx:key="*this"
<view wx:for="{{arr}}" wx:key="*this">{{item}}</view>
如果是对象数组,一般使用唯一值的字段,例如id
data: {
list: [
{id: 1, name: 'list1'},
{id: 2, name: 'list2'}
]
}
<view wx:for="{{list}}" wx:key="id">{{item.name}}</view>
进入正题,按照需求定义两个tab选项卡,如果tab选项过多可以使用scroll-view
<view class='flex-row tabbar'>
<text id="tabitemRecharge" class='tabitem {{activeTabId=="tabitemRecharge"?"tabitem-active":""}}' bindtap='tabclick'>充值记录</text>
<text id="tabitemConsume" class='tabitem {{activeTabId=="tabitemConsume"?"tabitem-active":""}}' bindtap='tabclick'>消费记录</text>
<view class='tabindicator' animation="{{indicatorAnim}}"></view>
</view>
<swiper class='scrollview-content' current-item-id='tabitemRecharge' bindchange='tabChange'>
<swiper-item item-id="tabitemRecharge">
<scroll-view scroll-y="true" class="tab-content recharge-list">
<view class='list-item recharge-item' wx:for="{{rechargeList}}" wx:for-item="rItem" wx:key="id">{{rItem.name}}</view>
</scroll-view>
</swiper-item>
<swiper-item item-id="tabitemConsume">
<scroll-view scroll-y="true" class="tab-content recharge-list">
<view class='list-item consume-item' wx:for="{{consumeList}}" wx:for-item="rItem" wx:key="id">{{rItem.name}}</view>
</scroll-view>
</swiper-item>
</swiper>
tab页面的数据结构如下
data: {
tabitemConsume: {}, // 存放tab选项卡的rect,键对应的内容swiper-item的item-id
tabitemRecharge: {}, // 存放tab选项卡的rect,键对应的内容swiper-item的item-id
activeTabId: null,
rechargeList: [],
consumeList: []
}
这里命名属性的方式是可以方便通过swiper-item的item-id来获取对应的tab选项卡的位置信息,例如
var rect = this.data[swiper-item-id];
wx.createSelectorQuery
要实现tab指示器的大小和位置动画,需要测量每个tab的rect(大小和位置)。微信没有提供丰富的dom操作api,但是提供了通过wx.createSelectorQuery来获取节点的信息
onReady() {
var query = wx.createSelectorQuery().in(this),
_this = this;
_this.animation = wx.createAnimation()
query.select('#tabitemConsume').boundingClientRect(function (rect) {
_this.setData({
tabitemConsume: rect
});
})
query.select('#tabitemRecharge').boundingClientRect(function (rect) {
_this.setData({
tabitemRecharge: rect
});
_this.setActiveTab('tabitemRecharge');
})
query.exec();
}
wx.createAnimation
小程序的动画用wx.createAnimation来实现,给元素设置一个animation属性,通过export方法来给animation属性赋值
每次调用export方法都会清空上一次设置动画,举个例子
<view style="width: 20px; height: 4px; background: #333;" animation="{{anim}}"></view>
this.animation = wx.createAnimation({
timingFunction: 'ease',
delay: 0
});
// width变成200,x位置移动到100的动画
this.animation.width(200).translate(100, 0).step();
this.setData({
anim: this.animation.export()
})
效果如下
tab指示器的动画
通过上面的wx.createAnimation就可以实现指示器的切换效果了
// tab选项卡激活设置动画
setActiveTab(id) {
var rect = this.data[id];
if (rect) {
this.animation.width(rect.width).translate(rect.left, 0);
this.setData({
activeTabId: id, // 激活的swiper视图
indicatorAnim: this.animation.step().export()
})
}
}
tab选项卡内容块
由于要实现滑动切换tab,用swiper来实现横向滑动,scroll-view来实现纵向滚动
swiper组件
swiper是滑块视图容器组件,可以用来实现幻灯片轮播效果等等。
<swiper class='scrollview-content' current-item-id='{{activeTabId}}' bindchange='tabChange'>
<swiper-item item-id="tabitemRecharge"></swiper-item>
<swiper-item item-id="tabitemConsume"></swiper-item>
</swiper>
swiper有一个current-item-id
属性,通过匹配swiper-item的item-id
属性来设置swiper指定的视图内容,在bindchange
事件获取视图的id指定对应的swiper的视图即可
tabChange(e) {
var id = e.detail.currentItemId;
this.setActiveTab(id);
}
附上效果地址