小程序模板網(wǎng)

微信小程序中實(shí)現(xiàn)仿今日頭條AppTopbar

發(fā)布時(shí)間:2018-04-14 14:46 所屬欄目:小程序開發(fā)教程
作者; 剪影Boy,來自授權(quán)地址

今日頭條App的Topbar是一個(gè)典型的頻道管理和切換組件,自己前段時(shí)間研究了一番,在微信小程序上也實(shí)現(xiàn)了類似的效果。

我們先看具體效果好了 ↓↓↓

這個(gè)項(xiàng)目(wx-topbar)已經(jīng)放在GitHub上了——點(diǎn)此前往,歡迎學(xué)習(xí)交流。

接下來,簡要說一下實(shí)現(xiàn)思路。

先看視圖層,Topbar橫向滾動(dòng)對(duì)應(yīng)的WXML代碼如下:

<scroll-view class="navbar" scroll-x="true" scroll-left="{{scrollNavbarLeft}}">
    <view class="navbar-item {{ navbarArray[item].type }}" id="{{ item }}" wx:for="{{ navbarShowIndexArray }}" catchtap="onTapNavbar">
        <view class="navbar-item-wrap">{{ navbarArray[item].text }}</view>
    </view>
    <view class="navbar-item visibility-hidden">
        <view class="navbar-item-wrap">空白</view>
    </view>
</scroll-view>
<view class="navbar-arrow-down" catchtap="showChannelSettingModal">
    <view class="navbar-arrow-down-wrap">
        <image class="navbar-arrow-icon" src="/images/index/icon_arrow_down.png"></image>
    </view>
</view>

scroll-view負(fù)責(zé)Topbar中各個(gè)頻道的呈現(xiàn),所有頻道的相關(guān)數(shù)據(jù)都存儲(chǔ)在navbarArray這個(gè)對(duì)象數(shù)組里,而數(shù)組navbarShowIndexArray里存儲(chǔ)了要顯示頻道在數(shù)組navbarArray中的索引。

不難猜測(cè),頻道是否選中高亮,與數(shù)組navbarArray有關(guān);頻道是否顯示,與數(shù)組navbarShowIndexArray有關(guān)。

點(diǎn)擊某個(gè)頻道名稱,就會(huì)觸發(fā)對(duì)應(yīng)頻道的切換操作。

view.navbar-arrow-down對(duì)應(yīng)的是右上角的向下箭頭,可采用fixed定位類型,點(diǎn)擊后彈出管理頻道的Modal.

<view class="channel-setting-modal {{ channelSettingModalShow }}" hidden="{{ channelSettingModalHide }}">
    <view class="channel-show-text">
        <view class="channel-show-text-wrap">顯示頻道</view>
    </view>
    <view class="channel-item" wx:for="{{ navbarShowIndexArray }}">
        <view class="channel-item-wrap">
            <view class="channel-item-left">
                <image class="channel-item-icon-minus {{ !index || navbarShowIndexArray.length < 4 ? 'visibility-hidden' : '' }}" id="{{ item }}.0" src="/images/index/icon_minus.png" catchtap="hideChannel"></image>
                <view class="channel-item-text">{{ navbarArray[item].text }}</view>
            </view>
            <view class="channel-item-up {{ index < 2 ? 'visibility-hidden' : '' }}" id="{{ item }}.00" catchtap="upChannel">上移</view>
        </view>
    </view>
    <view class="channel-hide-text">
        <view class="channel-hide-text-wrap">隱藏頻道</view>
    </view>
    <view class="channel-item" wx:for="{{ navbarHideIndexArray }}">
        <view class="channel-item-wrap">
            <view class="channel-item-left">
                <image class="channel-item-icon-plus" id="{{ item }}.0" src="/images/index/icon_plus.png" catchtap="showChannel"></image>
                <view class="channel-item-text">{{ navbarArray[item].text }}</view>
            </view>
            <view class="channel-item-up visibility-hidden">上移</view>
        </view>
    </view>
</view>

在這個(gè)管理頻道的Modal里,通過改變數(shù)組navbarShowIndexArray來控制頻道是否顯示和顯示順序,同時(shí),需要另外一個(gè)數(shù)組navbarHideIndexArray來存儲(chǔ)隱藏的頻道。

Modal顯示的時(shí)候,Topbar需要被另一個(gè)寫有“頻道設(shè)置”字樣的Bar覆蓋。

<view class="channel-setting {{ channelSettingShow }}">
    <view class="channel-setting-text">頻道設(shè)置</view>
    <view class="navbar-arrow-up" catchtap="hideChannelSettingModal">
        <image class="navbar-arrow-icon navbar-arrow-icon-up" src="/images/index/icon_arrow_up.png"></image>
    </view>
</view>

然后,我們來看邏輯層的實(shí)現(xiàn)。初始化的部分data如下:

data: {
    navbarArray: [{
        text: '推薦',
        type: 'navbar-item-active'
    }, {
        text: '熱點(diǎn)',
        type: ''
    }, {
        text: '視頻',
        type: ''
    }, {
        text: '圖片',
        type: ''
    }, {
        text: '段子',
        type: ''
    }, {
        text: '社會(huì)',
        type: ''
    }, {
        text: '娛樂',
        type: ''
    }, {
        text: '科技',
        type: ''
    }, {
        text: '體育',
        type: ''
    }, {
        text: '汽車',
        type: ''
    }, {
        text: '財(cái)經(jīng)',
        type: ''
    }, {
        text: '搞笑',
        type: ''
    }],
    navbarShowIndexArray: Array.from(Array(12).keys()),
    navbarHideIndexArray: [],
    channelSettingShow: '',
    channelSettingModalShow: '',
    channelSettingModalHide: true
}

navbar-item-active是一個(gè)可使頻道高亮的Class,navbarShowIndexArray初始化的結(jié)果是一個(gè)0到11的數(shù)組,剛好是數(shù)組navbarArray的所有元素的索引。顯然,初始化的結(jié)果是所有頻道都將顯示。

為了實(shí)現(xiàn)頻道個(gè)性化配置的保存,navbarShowIndexArray還需要通過小程序的數(shù)據(jù)緩存API儲(chǔ)存起來。

storeNavbarShowIndexArray: function() {
    const that = this;
    wx.setStorage({
        key: 'navbarShowIndexArray',
        data: that.data.navbarShowIndexArray
    });
}

切換頻道的函數(shù)如下:

switchChannel: function(targetChannelIndex) {
    this.getArticles(targetChannelIndex);

    let navbarArray = this.data.navbarArray;
    navbarArray.forEach((item, index, array) => {
        item.type = '';
        if (index === targetChannelIndex) {
            item.type = 'navbar-item-active';
        }
    });
    this.setData({
        navbarArray: navbarArray,
        currentChannelIndex: targetChannelIndex
    });
}

這樣,頻道的管理和簡單切換我們就實(shí)現(xiàn)了。

但是,到此為止,頻道的切換只能通過點(diǎn)擊對(duì)應(yīng)Topbar中頻道那一小塊區(qū)域來實(shí)現(xiàn),要是在正文區(qū)域左滑和右滑也能切換頻道就好了。

一個(gè)容易想到的思路是,在正文區(qū)域綁定touch事件,通過坐標(biāo)判斷滑動(dòng)方向,然后使Topbar中當(dāng)前頻道的上一個(gè)或下一個(gè)頻道高亮,同時(shí),控制Topbar橫向滾動(dòng)合適的偏移長度,以確保切換后的頻道能出現(xiàn)在視圖區(qū)域。

onTouchstartArticles: function(e) {
    this.setData({
        'startTouchs.x': e.changedTouches[0].clientX,
        'startTouchs.y': e.changedTouches[0].clientY
    });
},
onTouchendArticles: function(e) {
    let deltaX = e.changedTouches[0].clientX - this.data.startTouchs.x;
    let deltaY = e.changedTouches[0].clientY - this.data.startTouchs.y;
    if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 10) {
        let deltaNavbarIndex = deltaX > 0 ? -1 : 1;
        let currentChannelIndex = this.data.currentChannelIndex;
        let navbarShowIndexArray = this.data.navbarShowIndexArray;
        let targetChannelIndexOfNavbarShowIndexArray = navbarShowIndexArray.indexOf(currentChannelIndex) + deltaNavbarIndex;
        let navbarShowIndexArrayLength = navbarShowIndexArray.length;
        if (targetChannelIndexOfNavbarShowIndexArray >= 0 && targetChannelIndexOfNavbarShowIndexArray <= navbarShowIndexArrayLength - 1) {
            let targetChannelIndex = navbarShowIndexArray[targetChannelIndexOfNavbarShowIndexArray];
            if (navbarShowIndexArrayLength > 6) {
                let scrollNavbarLeft;
                if (targetChannelIndexOfNavbarShowIndexArray < 5) {
                    scrollNavbarLeft = 0;
                } else if (targetChannelIndexOfNavbarShowIndexArray === navbarShowIndexArrayLength - 1) {
                    scrollNavbarLeft = this.rpx2px(110 * (navbarShowIndexArrayLength - 6));
                } else {
                    scrollNavbarLeft = this.rpx2px(110 * (targetChannelIndexOfNavbarShowIndexArray - 4));
                }
                this.setData({
                    scrollNavbarLeft: scrollNavbarLeft
                });
            }
            this.switchChannel(targetChannelIndex);
        }
    }
}


本文地址:http://22321a.com/wxmini/doc/course/23383.html 復(fù)制鏈接 如需定制請(qǐng)聯(lián)系易優(yōu)客服咨詢:800182392 點(diǎn)擊咨詢
QQ在線咨詢