话不多说,先上一张效果图(没买会员,有水印,勿介意),如果是你想要的效果,继续往下看
原先做百度小程序的时候有现成的tab切换组件,然后改做微信小程序的时候,发现没有现成的组件是上图的效果,所以自己手动写了一个。
我这边的tab切换用的是scroll-view + swiper。切换选项的是scroll-view,如果不用scroll-view的话,在切到第五个的时候,第六个不会自动滑出来,用户体验感不好。底下使用swiper也是为了让内容切换的时候,有滑动的效果,提高用户体验。
一、初步完成tab切换
tab选项的处理:
1.给每个tab选项添加一个data-current的属性,绑上当前是第几个选项。(注意:这边的第1个绑的是0,第2个绑的是1,…)
2.给选中的tab选项添加一个类on(里面写选中时的样式)
3.给tab选项添加一个切换事件,swichNav
tab内容的处理:
1.swiper有一个current属性,值为当前是第几个元素,可以利用这一点,传一个数字currentTab(当前应该显示第几个)给current,从而显示对应的内容
2.给swiper添加切换事件,bindChange
swichNav事件的处理:
1.先在data中给currentTab一个默认值0,因为一般都是默认显示第一个.
2.比较当前点击的元素的data-current和当前选中的tab选项(即currentTab):
如果两个值一样,说明点击的就是当前选中的,就不做处理,
如果两个值不一样,就要将currentTab值改成当前点击的元素的data-current
swichNav事件的处理:
将当前的currentTab(当前应该显示第几个)传给current
wxml代码:
<view class="swiper-tab">
<scroll-view scroll-x="true" show-scrollbar="false" scroll-with-animation="true" style="width: 100%;white-space: nowrap;">
<block wx:for="{{provList}}" wx:key="i">
<view class="swiper-tab-list {{currentTab==index ? 'on' : ''}}" data-current="{{index}}" bindtap="swichNav">{{item.name}}</view>
</block>
</scroll-view>
<swiper current="{{currentTab}}" class="swiper-box" duration="300" bindchange="bindChange" style="height: {{tabsheight}};">
<block wx:for="{{cityList}}" wx:for-item="city" wx:key="n">
<swiper-item>
<view class="list">
<block wx:for="{{city}}" wx:key="u">
<view class="city-item">
<image class="img" src="{{item.img}}"></image>
<view class="text">{{item.city}}</view>
</view>
</block>
</view>
</swiper-item>
</block>
</swiper>
</view>
js代码:
Page({
data: {
currentTab:0
},
swichNav: function( e ) {
var that = this;
if( this.data.currentTab === e.target.dataset.current ) {
return false;
} else {
that.setData( {
currentTab: e.target.dataset.current
})
}
},
bindChange: function( e ) {
var that = this;
that.setData( {
currentTab: e.detail.current
});
},
})
二、实现tab滚动条滑动
想要让tab滚动条滑动,可以利用scroll-view中的 scroll-left属性。我们判断当前选中的个数是否是第5个,如果是,我们将当前的个数*tab选项的宽度赋给scroll-left.
wxml代码:
<scroll-view scroll-left="{{navScrollLeft}}" scroll-x="true" show-scrollbar="false" scroll-with-animation="true"style="width: 100%;white-space: nowrap;">
js代码:
swichNav: function( e ) {
var that = this;
if( this.data.currentTab === e.target.dataset.current ) {
return false;
} else {
that.setData( {
currentTab: e.target.dataset.current,
navScrollLeft:e.target.dataset.current >= 4 ? ((e.target.dataset.current) * 60) : 0 //判断当前选中的个数是否是第5个
})
}
},
bindChange: function( e ) {
var that = this;
that.setData( {
currentTab: e.detail.current,
navScrollLeft:e.detail.current >= 4 ? ((e.detail.current) * 60) : 0 //判断当前选中的个数是否是第5个
});
}
三、Swiper的高度自适应
swiper的高度不能自适应,默认高度150px,如果每个列表的长度不一样,也不能固定写死一个值,需要计算得出。网上有很多推荐根据列表的长度*元素的高度得到swiper的高度,但是这个方法只适用于swiper-item里面只有一个列表的,要是swiper-item里面有好几个列表的,就算不过来了。
我利用了SelectorQuery NodesRef.boundingClientRect(function callback)这个API获取一个元素的高度(我们可以把swiper-item里面有好几个列表包到这个元素里),然后把这个高度传给swiper。
这里需要注意的一点是,我们swiper有好多个swiper-item,我们必须给这个元素标上编号,以方便获取对应swiper-item的高度。
wxml代码:
<swiper current="{{currentTab}}" class="swiper-box" duration="300" bindchange="bindChange" style="height: {{tabsheight}};"> //tabsheight就是计算后的值
<block wx:for="{{cityList}}" wx:for-item="city" wx:key="n">
<swiper-item>
<view class="list list{{index}}"> //list{{index}}就是给每个list标上序号
/*好多个列表*/
</view>
</swiper-item>
</block>
</swiper>
js代码:
data: {
tabsheight:'450px' //默认高度
},
//计算swiper高度方法(在切换的时候调用)
tabsHeight(element){
let that = this;
let query = wx.createSelectorQuery(); //必须要先创建一个查询
query.select(element).boundingClientRect(function(rect){
that.setData({
tabsheight:rect.height + 'px'
});
}).exec();
},
swichNav: function( e ) {
var that = this;
if( this.data.currentTab === e.target.dataset.current ) {
return false;
} else {
that.setData( {
currentTab: e.target.dataset.current,
navScrollLeft:e.target.dataset.current >= 4 ? ((e.target.dataset.current) * 60) : 0
})
}
that.tabsHeight('.list'+e.target.dataset.current); //查询哪一个元素
},
bindChange: function( e ) {
var that = this;
that.setData( {
currentTab: e.detail.current,
navScrollLeft:e.detail.current >= 4 ? ((e.detail.current) * 60) : 0
});
that.tabsHeight('.list'+e.detail.current);//查询哪一个元素
},
})
因为这边的列表不是从接口里得到的,所以data中给一个默认高度,用于第一个swiper-item的渲染。如果列表是从接口里得到的,就不需要在data中加tabsheight了,直接得到值的时候调用一次tabsHeight方法就行。如果你遇到没有第一次的高度没有加上,是因为还没有渲染完成就调用tabsHeight方法了,所以给它加个定时器,等渲染完成,再计算高度
setTimeout(() => {
that.tabsHeight('.list0');
},1000)
完整代码
wxml代码:
<view class="container">
<view class="swiper-tab">
<scroll-view scroll-x="true" show-scrollbar="false" scroll-with-animation="true" scroll-left="{{navScrollLeft}}" style="width: 100%;white-space: nowrap;">
<block wx:for="{{provList}}" wx:key="i">
<view class="swiper-tab-list {{currentTab==index ? 'on' : ''}}" data-current="{{index}}" bindtap="swichNav">{{item.name}}</view>
</block>
</scroll-view>
</view>
<swiper current="{{currentTab}}" class="swiper-box" duration="300" bindchange="bindChange" style="height: {{tabsheight}};">
<block wx:for="{{cityList}}" wx:for-item="city" wx:key="n">
<swiper-item>
<view class="list list{{index}}">
<block wx:for="{{city}}" wx:key="u">
<view class="city-item">
<image class="img" src="{{item.img}}"></image>
<view class="text">{{item.city}}</view>
</view>
</block>
</view>
</swiper-item>
</block>
</swiper>
<view>底部</view>
</view>
wxss代码:
.swiper-tab{
width: 100%;
text-align: center;
line-height: 80rpx;
}
.swiper-tab-list{
font-size: 30rpx;
display: inline-block;
min-width: 18%;
max-width: 18%;
margin: 0 1%;
}
.on{ color: black;
font-weight: bold;
border-bottom: 4rpx solid black;
}
.swiper-box{
display: block;
height: 700px;
width: 100%;
margin-top: 10px;
}
.city-item{
width: 100%;
display: flex;
flex-flow: row nowrap;
margin-bottom: 10px;
}
.img{
width: 40%;
height: 100px;
}
.text{
width: 60%;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
border: 1px solid #ddd;
box-sizing: border-box;
}
js代码:
Page({
data: {
currentTab:0,
tabsheight:'450px',
provList:[
{"name":"江苏"},
{"name":"浙江"},
{"name":"上海"},
{"name":"河南"},
{"name":"河北"},
{"name":"重庆"},
{"name":"天津"},
{"name":"广东"},
],
cityList:[
[{"img":"/imgs/default.jpg","city":"南京"},
{"img":"/imgs/default.jpg","city":"苏州"},
{"img":"/imgs/default.jpg","city":"南通"},
{"img":"/imgs/default.jpg","city":"无锡"}],
[{"img":"/imgs/default.jpg","city":"杭州"},
{"img":"/imgs/default.jpg","city":"宁波"},
{"img":"/imgs/default.jpg","city":"温州"}],
[{"img":"/imgs/default.jpg","city":"上海"}],
[{"img":"/imgs/default.jpg","city":"郑州"},
{"img":"/imgs/default.jpg","city":"开封"},
{"img":"/imgs/default.jpg","city":"洛阳"},
{"img":"/imgs/default.jpg","city":"周口"}],
[{"img":"/imgs/default.jpg","city":"石家庄"},
{"img":"/imgs/default.jpg","city":"唐山"},
{"img":"/imgs/default.jpg","city":"秦皇岛"}],
[{"img":"/imgs/default.jpg","city":"重庆"}],
[{"img":"/imgs/default.jpg","city":"天津"}],
[{"img":"/imgs/default.jpg","city":"广州"},
{"img":"/imgs/default.jpg","city":"深圳"}]
]
},
tabsHeight(element){
let that = this;
let query = wx.createSelectorQuery();
query.select(element).boundingClientRect(function(rect){
that.setData({
tabsheight:rect.height + 'px'
});
}).exec();
},
swichNav: function( e ) {
var that = this;
if( this.data.currentTab === e.target.dataset.current ) {
return false;
} else {
that.setData( {
currentTab: e.target.dataset.current,
navScrollLeft:e.target.dataset.current >= 4 ? ((e.target.dataset.current) * 60) : 0
})
}
that.tabsHeight('.list'+e.target.dataset.current);
},
bindChange: function( e ) {
var that = this;
that.setData( {
currentTab: e.detail.current,
navScrollLeft:e.detail.current >= 4 ? ((e.detail.current) * 60) : 0
});
that.tabsHeight('.list'+e.detail.current);
},
})