Open kujian opened 6 years ago
今天在做百度小程序的转换,发现真机上用之前的swiper-item结合scroll-view 的效果不理想,于是我重新思考,发现了一种更合适的方案。
https://github.com/zhongjie-chen/wx-scrollable-tab-view 在网上找到这个人使用touch事件,我试着用他的方法,很好用,但是有一点缺陷,就是手指切换有时候不灵敏,有时候我已经滑动很长了,但它没有切换到下一屏,还在当前屏停留。然后我认真的看了他的实现,发现他里面解决了这个scroll-view定位由于滑动到下一屏会重置的问题。
他是怎么解决的呢?就是每一个切换里面又加多了一个scroll-view。这样子就避免了切换时历史滚动位置需要重置的问题。于是我想到了既然用他这种做法解决了我前面的缺陷,那我把两个结合起来,不就完美解决了。
首先是使用swiper组件解决切换问题,然后就是每个swiper-item里面加一个scroll-view组件,这样子就不需要每次切换都要计算历史滚动位置了。效果非常流畅,JS只需要几个常规的函数就解决了,不需要hack,完美的解决方案。
wxml:
<!--pages/live/live.wxml--> <view class="g-doc"> <view class="tab"> <view class="tab-inner"> <scroll-view class="scroll-bangdan" scroll-x="true" scroll-left="{=scrollLeft=}"> <view class="ctrl" style="width:1054rpx"> <block s-for="item, index in nav" s-key="{{item.columnId}}"> <view class="toc{{current==index?' cur':''}}" bindtap="changeTab" data-index="{{index}}"> <view class="text"> <text>{{item.columnName}}</text> </view> </view> </block> </view> </scroll-view> <view class="mask"></view> </view> </view> <view class="tab-container"> <swiper current="{{current}}" class="swiper-box" duration="300" bindchange="bindchange"> <block s-for="item, index in nav" s-key="{{item.columnId}}"> <swiper-item> <block s-if="list[item.columnId].data.length>0"> <scroll-view style="height:100%" scroll-y="true" bindscrolltolower="loadMoreList"> <view class="list"> <block s-for="art, index in list[item.columnId].data" s-key="{{art.id}}"> <view class="item"> <navigator url="../art/art?id={{art.id}}" hover-class="none" open-type="navigate"> <view class="img"> <image mode src="{{art.imageUrl}}"></image> <view class="meta"> <view class="avatar"> <image src="{{art.userImage}}"></image> </view> <view class="nickName"> <text>{{art.userName}}</text> </view> </view> </view> <view class="title">{{art.title}}</view> <view class="des">{{art.summary}}</view> </navigator> </view> </block> <view class="m-end" hidden="{{list[curListId].endTipHidden}}"> <block s-if="endTip=='正在加载'"> <view class="icon"></view> </block> {{endTip}} </view> <view class="m-end" hidden="{{!list[curListId].endTipHidden}}">没有更多了</view> </view> </scroll-view> </block> </swiper-item> </block> </swiper> </view> </view>
js:
// pages/live/live.js const config = require('../../pc.config.js'); Page({ /** * 页面的初始数据 */ data: { nav: [{ "columnName": '全部', "columnId": "000081525" }, { "columnName": '好物种草', "columnId": "000084624" }, { "columnName": '收纳支招', "columnId": "000084644" }, { "columnName": '细节控', "columnId": "000084645" }, { "columnName": '小改造', "columnId": "000084625" }, { "columnName": '洗刷刷', "columnId": "000084626" }, { "columnName": '睡眠研究', "columnId": "000084646" }], list: {}, curListId: 0, endTipHidden: false, endTip: '正在加载', current: 0, scrollLeft: 0, loading: false }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { var index = options.index || 0; this.getNav(index); }, timer: null, //获取导航和节点 getNav: function (index) { var self = this; swan.request({ url: config.getAPI('liveNav'), success: function (res) { // console.log(res); self.setData({ nav: res.data.livingColumn, current: index }); //获取导航的初始位置 if (index > res.data.livingColumn.length / 2) { self.setData({ scrollLeft: 1054 / 2 }); } self.getList(res.data.livingColumn[index].columnId); } }); }, //滑到底部加载更多 loadMoreList: function () { var self = this; clearTimeout(self.timer); self.timer = null; self.timer = setTimeout(function () { var list = self.data.list; var cid = self.data.curListId; if (list[cid].pageNo < list[cid].pageCount) { self.getList(cid); } }, 300); }, //请求列表 getList: function (cid) { var self = this; this.setData({ curListId: cid }); var list = this.data.list; if (this.data.loading) return; this.setData({ loading: true }) if (!list[cid] || (list[cid] && (list[cid].pageNo < list[cid].pageCount))) { var pageNo = !list[cid] ? 1 : list[cid].pageNo + 1; swan.request({ url: config.getAPI('liveList') + `?columnType=livingColumn&columnId=${cid}&pageSize=10&pageNo=${pageNo}`, success: function (res) { // console.log(res.data); var obj = {}; obj.pageNo = res.data.pageNo; obj.pageCount = Math.ceil(res.data.total / res.data.pageSize); obj.total = res.data.total; obj.data = !list[cid] ? res.data.data : list[cid].data.concat(res.data.data); obj.swiperHeight = 1110; obj.swiperHeight = res.data.total > res.data.pageSize * res.data.pageNo ? res.data.pageSize * res.data.pageNo * 518 + 102 : res.data.total * 518 + 102; if (res.data.pageNo * res.data.pageSize >= res.data.total) { obj.endTip = '没有更多了'; obj.endTipHidden = true; } else { obj.endTip = '正在加载'; } list[cid] = obj; self.setData({ list, loading: false }); }, fail: function () { swan.showModal({ title: '提示', content: '加载不成功,是否重新加载?', confirmText: "重新加载", success: function (res) { self.setData({ loading: false }) if (res.confirm) { self.loadMoreList(); } else if (res.cancel) { // console.log('用户点击取消') } } }); } }); } }, switchNav: function (index) { if (index && this.data.current == index) return; var cid = this.data.nav[index].columnId; var self = this; var scrollLeft = 0; if (index > this.data.nav.length / 2) { scrollLeft = 1054 / 2; } var list = self.data.list; if (!list[cid]) { clearTimeout(self.timer); self.timer = null; self.timer = setTimeout(function () { self.setData({ curListId: cid, current: index, scrollLeft }); self.getList(cid); }, 500); } else { self.setData({ curListId: cid, current: index, scrollLeft }); } }, //切换导航 changeTab: function (e) { // console.log('changetab'); var index = e.currentTarget.dataset.index; this.switchNav(index); }, //滑动swiper bindchange: function (e) { // console.log('changeswiper'); var index = e.detail.current; if (e.detail.source && e.detail.source == 'touch') { this.switchNav(index); } }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { return { path: '/pages/live/live?index=' + this.data.current }; } });
/* pages/live/live.css */ page { height: 100%; overflow: hidden; } .g-doc { height: 100%; } .tab { position: fixed; top: 0; left: 0; border-bottom: 1px solid #f8f8f8; background: #fff; z-index: 1; width: 100%; height: 100rpx; line-height: 100rpx; } .tab-inner{ height: 100rpx; overflow: hidden; } /* .tab-con{width: 100%;} */ .scroll-bangdan { width: 100%; position: relative; height: 130rpx; } .tab .ctrl { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; flex-flow: row wrap; -webkit-flex: row wrap; font-size: 28rpx; height: 100rpx; line-height: 100rpx; } .tab .ctrl .toc { text-align: center; margin-left: 50rpx; white-space: nowrap; } .tab .ctrl .toc:first-child { margin-left: 40rpx; } .tab .ctrl .toc:last-child { margin-right: 40rpx; } .tab .ctrl .toc .text { display: inline-block; position: relative; } .tab .ctrl .toc.cur .text::before { content: "\20"; display: block; position: absolute; height: 10rpx; background: #fbe251; left: 0; bottom: 30rpx; width: 100%; z-index: 0; } .tab .ctrl .toc .text text { position: relative; z-index: 2; } .tab .mask { background: url(https://www1.pchouse.com.cn/2018/weixinminipro/mask.png) no-repeat top right; background-size: 113rpx; width: 83rpx; height: 100rpx; position: fixed; right: 0; top: 0; z-index: 50; } .swiper-box{position: absolute; left: 0; width: 100%; height: 100%; top: 0;} .list { padding-top: 100rpx; } .list .item { padding: 30rpx 40rpx 40rpx; } .list .item .img { width: 670rpx; height: 336rpx; overflow: hidden; position: relative; border-radius: 16rpx; } .list .item .meta { position: absolute; left: 0; bottom: 0; height: 84rpx; width: 100%; padding-top: 16rpx; line-height: 60rpx; color: #fff; font-size: 28rpx; overflow: hidden; background: url(https://www1.pchouse.com.cn/2018/weixinminipro/pic-modal.png?v2) repeat-x center bottom; background-size: auto 99rpx; } .list .item .meta .avatar { width: 60rpx; height: 60rpx; float: left; margin-left: 24rpx; margin-right: 24rpx; } .list .item .meta .avatar image { width: 60rpx; height: 60rpx; border-radius: 100%; } .list .item .meta .nickName { float: left; } .list .item .img image { width: 670rpx; height: 336rpx; border-radius: 16rpx; } .list .item .title { height: 73rpx; line-height: 73rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 36rpx; } .list .item .des { height: 40rpx; overflow: hidden; font-size: 24rpx; color: #aaa; text-overflow: ellipsis; white-space: nowrap; } .m-end { padding: 20rpx 0 34rpx; line-height: 28rpx; }
原文:http://caibaojian.com/xiaochengxu-tabview.html
今天在做百度小程序的转换,发现真机上用之前的swiper-item结合scroll-view 的效果不理想,于是我重新思考,发现了一种更合适的方案。
之前的缺陷
解决方法
https://github.com/zhongjie-chen/wx-scrollable-tab-view 在网上找到这个人使用touch事件,我试着用他的方法,很好用,但是有一点缺陷,就是手指切换有时候不灵敏,有时候我已经滑动很长了,但它没有切换到下一屏,还在当前屏停留。然后我认真的看了他的实现,发现他里面解决了这个scroll-view定位由于滑动到下一屏会重置的问题。
他是怎么解决的呢?就是每一个切换里面又加多了一个scroll-view。这样子就避免了切换时历史滚动位置需要重置的问题。于是我想到了既然用他这种做法解决了我前面的缺陷,那我把两个结合起来,不就完美解决了。
首先是使用swiper组件解决切换问题,然后就是每个swiper-item里面加一个scroll-view组件,这样子就不需要每次切换都要计算历史滚动位置了。效果非常流畅,JS只需要几个常规的函数就解决了,不需要hack,完美的解决方案。
代码如下
wxml:
js:
原文:http://caibaojian.com/xiaochengxu-tabview.html