小程序之tab如何實現swiper自適應高度,并記錄滾動位置?

2018-10-31 1901 0 編輯:深正互聯 來源:互聯網

移動端中需要使用swiper插件實現tab切換和手勢滑動的(類似于今日頭條資訊列表),在各種APP上我們可以很常見,但在小程序上實現這個看起來有點難,swiper插件滑動到下一屏的時候位置總是會回到跟上一屏相同的位置。我記得微信剛出來不久,有一個這樣子的需求,那時候是另外一個同事在跟,跟我說到過這個功能無法實現。最近我也接到這個需求,于是我認真的看了一下微信組件文檔,發現swiper+scroll-view組件結合是可以實現這個功能。


需要說的是,我的每個swiper-item數據不是固定的,每個swiper-item列表數據都有滾動底部會無線加載,所以說我無法在一開始就確定了所有的子項的高度,另外每個swiper-item都需要滾動,這就是說它們的滾動到的位置每個都不是一樣的。每次滑動到下一屏的時候,要確定最外層的scroll-view的scroll-top值。


自適應高度

由于swiper組件并不是自適應高度的,而我們每個swiper-item的高度并不是一樣的,所以第一步就是計算每個swiper-item的高度,并賦值給swiper組件。WXML代碼如下:

<swiper current="{{current}}" style="height:{{list[curListId].swiperHeight}}rpx;" class="swiper-box" duration="300" bindchange="bindchange">

    <block wx:for="{{nav}}">

        <swiper-item>

            <block wx:if="{{list[item.columnId].data.length>0}}">

                <view class="list">

                    <block wx:for="{{list[item.columnId].data}}" wx:for-item="art">

                        <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>

            </block>

        </swiper-item>

    </block>

</swiper>


可以看到我里面定義了一個循環,把所有子項的數據都放在list里面。當然前提我們已經知道要判斷的list[item.columnId]是否已經存在值,如果沒有我們需要先請求數據。而每個對象對應的下標我們已經知道,所以我們一開始進來就確認了所有swiper-item要加載的內容,后續滑動加載內容時如果沒有,我們就會去請求,如果有則使用,并且滑動到底部時,我們根據curListId知道當前需要請求那個對象。把剩下的數據合并在同一個對象里面。


計算swiper-item的高度,可以使用微信提供的一個 api createSelectorQuery,我這里沒用,因為我的列表每一個字內容都是固定好高度的。所以我只要知道獲取的數據數組的長度是多少,然后計算每個子項的高度,就能得到swiper-item的高度了。


記錄滾動值

記錄滾動值,這個很簡單,因為我們的頁面最外層就是一個scroll-view組件,所以我們只要給這個scroll-view一個bindscroll事件,在滾動的過程中,不斷的記錄更新每一個子項它最后滾動到的位置,下次進入這一屏,就看看數據里面有沒有這個滾動值,沒有的話,就是第一次進入,默認為0,如果有值,說明之前我們已經滾動過一次,則賦值給scroll-view的scroll-top。

scroll: function(e) {

    var self = this;

    setTimeout(function() {

        console.log(e.detail.scrollTop);

        var list = self.data.list;

        if (list[self.data.curListId]) {

            list[self.data.curListId].scrollTop = e.detail.scrollTop;

            self.setData({

                list

            })

        }

    }, 300);

},


預覽和代碼下載

就是實現這種常見的資訊tab列表,需要滑動加載數據,切換自動回到上次滾動的位置。


小程序

JS:

const app = getApp()

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"

        }],

        navPosition: [],

        list: {},

        curListId: 0,

        endTipHidden: false,

        endTip: '正在加載',

        current: 0,

        scrollLeft: 0,

        px2rpx: 2,

        winWidth: 375,

        scrollTop: 0

    },


    /**

     * 生命周期函數--監聽頁面加載

     */

    onLoad: function(options) {

        var index = options.index || 0;

        this.getSystem();

        this.getNav(index);

    },

    timer: null,

    getSystem: function() {

        var self = this;

        wx.getSystemInfo({

            success: function(res) {

                console.log(res);

                self.setData({

                    winWidth: res.windowWidth,

                    px2rpx: 750 / res.windowWidth

                })

            },

        });


    },

    //獲取導航和節點

    getNav: function(index) {

        var self = this;

        wx.request({

            url: config.getAPI('liveNav'),

            success: function(res) {

                //   console.log(res);

                self.setData({

                    nav: res.data.livingColumn,

                    current: index

                });

                //獲取導航的初始位置

                const query = wx.createSelectorQuery()

                query.selectAll('.toc').boundingClientRect();

                //   query.selectViewport().scrollOffset()

                query.exec(function(res) {

                    console.log(res);

                    console.log(res[index]);

                    self.setData({

                        navPosition: res[0]

                    })

                    if (index >= 4) {

                        self.setData({

                            scrollLeft: res[0][index].left

                        })

                    }

                })


                self.getList(res.data.livingColumn[index].columnId);

            }

        })

    },

    //滑到底部加載更多

    loadMoreList: function() {

        var list = this.data.list;

        var cid = this.data.curListId;

        if (list[cid].pageNo < list[cid].pageCount) {

            this.getList(cid);

        }

    },

    //請求列表

    getList: function(cid) {

        var self = this;

        this.setData({

            curListId: cid

        })

        var list = this.data.list;

        if (!list[cid]) {

            wx.request({

                url: config.getAPI('liveList') + `?columnType=livingColumn&columnId=${cid}&pageSize=10&pageNo=1`,

                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 = res.data.data;

                    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

                    })

                }

            })

        } else {

            if (list[cid].pageNo < list[cid].pageCount) {

                wx.request({

                    url: config.getAPI('liveList') + `?columnType=livingColumn&columnId=${cid}&pageSize=10&pageNo=${list[cid].pageNo+1}`,

                    success: function(res) {

                        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].data.concat(res.data.data);

                        if (res.data.pageNo * res.data.pageSize >= res.data.total) {

                            obj.endTip = '沒有更多了';

                            obj.endTipHidden = true;

                        } else {

                            obj.endTip = '正在加載';

                        }

                        obj.swiperHeight = res.data.total > res.data.pageSize * res.data.pageNo ? res.data.pageSize * res.data.pageNo * 518 + 102 : res.data.total * 518 + 102;

                        list[cid] = obj;

                        self.setData({

                            list

                        })

                    }

                })

            }

        }

    },

    //切換導航(包含滑動swiper和切換導航跳轉)

    switchNav: function(index) {

        if (index && this.data.current == index) return;

        console.log('switchtab');

        var cid = this.data.nav[index].columnId;

        var self = this;

        var scrollLeft = 0;

        if (self.data.navPosition[index].right * self.data.px2rpx + 62 >= 750) {

            scrollLeft = self.data.navPosition[index].left;

        }

        var list = self.data.list;

        var scrollTop = 0;

        if (list[cid] && list[cid].scrollTop) {

            scrollTop = list[cid].scrollTop

        }


        if (!list[cid]) {

            clearTimeout(self.timer);

            self.timer = null;

            self.timer = setTimeout(function() {


                self.setData({

                    curListId: cid,

                    current: index,

                    scrollLeft,

                    scrollTop

                })

                self.getList(cid);

            }, 500);

        } else {

            self.setData({

                curListId: cid,

                current: index,

                scrollLeft,

                scrollTop

            })

        }


    },

    //切換導航

    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;

        //加上這個避免swiper過程,swiper-item會發生滑動混亂,滑動過快就會一直在閃動,新的API屬性,touch說明是用戶接觸滑動,而不是自動滑動

        if (e.detail.source && e.detail.source =='touch'){

            this.switchNav(index);

        }

        

    },

    //滾動記錄之前的滾動位置

    scroll: function(e) {

        var self = this;

        setTimeout(function() {

            console.log(e.detail.scrollTop);

            var list = self.data.list;

            if (list[self.data.curListId]) {

                list[self.data.curListId].scrollTop = e.detail.scrollTop;

                self.setData({

                    list

                })

            }

        }, 300);

    },

})


WXML:

<scroll-view class="g-doc" scroll-y="true" bindscrolltolower="loadMoreList" scroll-top="{{scrollTop}}" bindscroll="scroll">

    <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 wx:for="{{nav}}">

                        <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}}" style="height:{{list[curListId].swiperHeight}}rpx;" class="swiper-box" duration="300" bindchange="bindchange">

            <block wx:for="{{nav}}">

                <swiper-item>

                    <block wx:if="{{list[item.columnId].data.length>0}}">

                        <view class="list">

                            <!-- <view class="nodata">這里空空如也</view> -->

                            <block wx:for="{{list[item.columnId].data}}" wx:for-item="art">

                                <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>

                    </block>

                </swiper-item>

            </block>

        </swiper>


        <view class="m-end" hidden="{{list[curListId].endTipHidden}}">

            <block wx:if="{{endTip=='正在加載'}}">

                <view class="icon"></view>

            </block>

            {{endTip}}

        </view>

        <view class="m-end" hidden="{{!list[curListId].endTipHidden}}">沒有更多了</view>

    </view>

</scroll-view>


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;

}


.list {

    padding-top: 100rpx;

}


.list .item {

    padding: 30rpx 40rpx 40rpx;

}


.list .item .img {

    width: 670rpx;

    height: 336rpx;

    overflow: hidden;

    position: relative;

}


.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;

}

本站文章均為深正網站建設摘自權威資料,書籍,或網絡原創文章,如有版權糾紛或者違規問題,請即刻聯系我們刪除,我們歡迎您分享,引用和轉載,但謝絕直接搬磚和抄襲!感謝...
關注深正互聯
七星彩头尾 在县里干什么赚钱 打麻将技巧十句口诀 现在女人赚钱容易 柳州飞鹅做什么赚钱 雷速体育直播比方 一个网吧怎么赚钱 不卖隔夜肉如何赚钱 篮球比分直播网 杭州边锋靠啥赚钱 电商平台运费怎么赚钱 nba数据库新浪体育 河北十一选五 哈尔滨小旅馆赚钱吗 抖音上那些做水果干茶的赚钱吗 老有内蒙古麻将下载挂 全球即时比分网直播