微信小程序-tab切换(scroll-view + swiper)

话不多说,先上一张效果图(没买会员,有水印,勿介意),如果是你想要的效果,继续往下看

原先做百度小程序的时候有现成的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);
  },
})
  • 4
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值