评论

自定义tabbar 【恋爱小清单开发总结】

自定义tabbar

看官方demo的小伙伴知道,自定义tabbar需要在小程序根目录底下建一个名叫custom-tab-bar的组件(我有试过,如果放在components目录里面小程序会识别不了),目前我自己实现的效果是:通过在配置可以切换tab,也可以点击tab后重定向到新页面,支持隐藏tabbar,同时也可以显示右上角文本和小红点。

官方demo里面用的是cover-view,我改成view,因为如果页面有弹窗的话我希望可以盖住tabbar

总结一下有以下注意点:

1、tabbar组件的目录命名需要是custom-tab-bar

2、app.json增加自定义tabbar配置

3、wx.navigateTo不允许跳转到tabb页面

4、进入tab页面时,需要调用tabbar.js手动切换tab


效果图:

可以扫码体验

代码目录如下:

代码如下:

app.json增加自定义tabbar配置

"tabBar": {
  "custom": true,
  "color": "#7A7E83",
  "selectedColor": "#3cc51f",
  "borderStyle": "black",
  "backgroundColor": "#ffffff",
  "list": [
    {
      "pagePath": "pages/love/love",
      "text": "首页"
    },
    {
      "pagePath": "pages/tabbar/empty",
      "text": "礼物说"
    },
    {
      "pagePath": "pages/tabbar/empty",
      "text": "恋人圈"
    },
    {
      "pagePath": "pages/me/me",
      "text": "我"
    }
  ]
},


自定义tabbar组件代码如下

index.js

//api.js是我自己对微信接口的一些封装
const api = require('../utils/api.js');
//获取应用实例
const app = getApp();
Component({
    data: {
        isPhoneX: false,
        selected: 0,
        hide: false,
        list: [{
            showRedDot: false,
            showBadge: false,
            badgeText: "",
            pagePath: "/pages/love/love",
            iconPath: "/images/tabbar/home.png",
            selectedIconPath: "/images/tabbar/home-select.png",
            text: "首页"
        }, {
            showRedDot: false,
            showBadge: false,
            badgeText: "",
            pagePath: "/pages/tabbar/empty",
            navigatePath: "/pages/gifts/giftList",
            iconPath: "/images/tabbar/gift.png",
            selectedIconPath: "/images/tabbar/gift-select.png",
            text: "礼物说",
            hideTabBar: true
        }, {
            showRedDot: false,
            showBadge: false,
            badgeText: "",
            pagePath: "/pages/tabbar/empty",
            navigatePath: "/pages/moments/moments",
            iconPath: "/images/tabbar/lover-circle.png",
            selectedIconPath: "/images/tabbar/lover-circle-select.png",
            text: "恋人圈",
            hideTabBar: true
        }, {
            showRedDot: false,
            showBadge: false,
            badgeText: "",
            pagePath: "/pages/me/me",
            iconPath: "/images/tabbar/me.png",
            selectedIconPath: "/images/tabbar/me-select.png",
            text: "我"
        }]
    },
    ready() {
        // console.error("custom-tab-bar ready");
        this.setData({
            isPhoneX: app.globalData.device.isPhoneX
        })
    },
    methods: {
        switchTab(e) {
            const data = e.currentTarget.dataset;
            console.log("tabBar参数:", data);
            api.vibrateShort();
            if (data.hideTabBar) {
                api.navigateTo(data.navigatePath);
            } else {
                /*this.setData({
                    selected: data.index
                }, function () {
                    wx.switchTab({url: data.path});
                });*/
                /**
                 * 改为直接跳转页面,
                 * 因为发现如果先设置selected的话,
                 * 对应tab图标会先选中,然后页面再跳转,
                 * 会出现图标变成未选中然后马上选中的过程
                 */
                wx.switchTab({url: data.path});
            }
        },

        /**
         * 显示tabbar
         * @param e
         */
        showTab(e){
            this.setData({
                hide: false
            }, function () {
                console.log("showTab执行完毕");
            });
        },

        /**
         * 隐藏tabbar
         * @param e
         */
        hideTab(e){
            this.setData({
                hide: true
            }, function () {
                console.log("hideTab执行完毕");
            });
        },

        /**
         * 显示小红点
         * @param index
         */
        showRedDot(index, success, fail) {
            try {
                const list = this.data.list;
                list[index].showRedDot = true;
                this.setData({
                    list
                }, function () {
                    typeof success == 'function' && success();
                })
            } catch (e) {
                typeof fail == 'function' && fail();
            }
        },

        /**
         * 隐藏小红点
         * @param index
         */
        hideRedDot(index, success, fail) {
            try {
                const list = this.data.list;
                list[index].showRedDot = false;
                this.setData({
                    list
                }, function () {
                    typeof success == 'function' && success();
                })
            } catch (e) {
                typeof fail == 'function' && fail();
            }
        },

        /**
         * 显示tab右上角文本
         * @param index
         * @param text
         */
        showBadge(index, text, success, fail) {
            try {
                const list = this.data.list;
                Object.assign(list[index], {showBadge: true, badgeText: text});
                this.setData({
                    list
                }, function () {
                    typeof success == 'function' && success();
                })
            } catch (e) {
                typeof fail == 'function' && fail();
            }
        },

        /**
         * 隐藏tab右上角文本
         * @param index
         */
        hideBadge(index, success, fail) {
            try {
                const list = this.data.list;
                Object.assign(list[index], {showBadge: false, badgeText: ""});
                this.setData({
                    list
                }, function () {
                    typeof success == 'function' && success();
                })
            } catch (e) {
                typeof fail == 'function' && fail();
            }
        }
    }
});

index.html

<view class="footer-tool-bar flex-center {{isPhoneX? 'phx_68':''}}" hidden="{{hide}}">
    <view class="tab flex-full {{selected === index ? 'focus':''}}"
          wx:for="{{list}}"
          wx:key="index"
          data-path="{{item.pagePath}}"
          data-index="{{index}}"
          data-navigate-path="{{item.navigatePath}}"
          data-hide-tab-bar="{{item.hideTabBar}}"
          data-open-ext-mini-program="{{item.openExtMiniProgram}}"
          data-ext-mini-program-app-id="{{item.extMiniProgramAppId}}"
          bindtap="switchTab">
        <view class="text">
            <view class="dot" wx:if="{{item.showRedDot}}"></view>
            <view class="badge" wx:if="{{item.showBadge}}">{{item.badgeText}}</view>
            <image class="icon" src="{{item.selectedIconPath}}" hidden="{{selected !== index}}"></image>
            <image class="icon" src="{{item.iconPath}}" hidden="{{selected === index}}"></image>
        </view>
    </view>
</view>
    

index.json

{
  "component": true,
  "usingComponents": {}
}


index.wxss

@import "/app.wxss";
.footer-tool-bar{
    background-color: #fff;
    height: 100rpx;
    width: 100%;
    position: fixed;
    bottom: 0;
    z-index: 100;
    text-align: center;
    font-size: 24rpx;
    transition: transform .3s;
    border-radius: 30rpx 30rpx 0 0;
    /*padding-bottom: env(safe-area-inset-bottom);*/
    box-shadow:0rpx 0rpx 18rpx 8rpx rgba(212, 210, 211, 0.35);
}
.footer-tool-bar .tab{
    color: #242424;
    height: 100%;
    line-height: 100rpx;
}
.footer-tool-bar .focus{
    color: #f96e49;
    font-weight: 500;
}
.footer-tool-bar .icon{
    width: 44rpx;
    height: 44rpx;
    margin: 18rpx auto;
}
.footer-tool-bar .text{
    line-height: 80rpx;
    height: 80rpx;
    position: relative;
    display: inline-block;
    padding: 0rpx 40rpx;
    box-sizing: border-box;
    margin: 10rpx auto;
}
.footer-tool-bar .dot{
    position: absolute;
    top: 16rpx;
    right: 16rpx;
    height: 16rpx;
    width: 16rpx;
    border-radius: 50%;
    background-color: #f45551;
}
.footer-tool-bar .badge{
    position: absolute;
    top: 8rpx;
    right: 8rpx;
    height: 30rpx;
    width: 30rpx;
    line-height: 30rpx;
    border-radius: 50%;
    background-color: #f45551;
    color: #fff;
    text-align: center;
    font-size: 20rpx;
    font-weight: 450;
}
.hide{
    transform: translateY(100%);
}


app.wxss(这里的样式文件是我用来存放一些公共样式)

/**app.wxss**/
page {
    background-color: #f5f5f5;
    height: 100%;
    -webkit-overflow-scrolling: touch;
}

.container {
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    box-sizing: border-box;
}

.blur {
    filter: blur(80rpx);
    opacity: 0.65;
}

.flex-center {   
    display: flex;
    align-items: center;
    justify-content: center;
}

.flex-column {
    display: flex;
    /*垂直居中*/
    align-items: center;
    /*水平居中*/
    justify-content: center;
    flex-direction: column;
}

.flex-start-horizontal{
    display: flex;
    justify-content: flex-start;
}
.flex-end-horizontal{
    display: flex;
    justify-content: flex-end;
}

.flex-start-vertical{
    display: flex;
    align-items: flex-start;
}
.flex-end-vertical{
    display: flex;
    align-items: flex-end;
}

.flex-wrap {
    display: flex;
    flex-wrap: wrap;
}

.flex-full {
    flex: 1;
}

.reset-btn:after {
    border: none;
}

.reset-btn {
    background-color: #ffffff;
    border-radius: 0;
    margin: 0;
    padding: 0;
    overflow: auto;
}

.loading{
    opacity: 0;
    transition: opacity 1s;
}

.load-over{
    opacity: 1;
}

.phx_68{
    padding-bottom: 68rpx;
}

.phx_34{
    padding-bottom: 34rpx;
}


另外我还对tabbar的操作做了简单的封装:

tabbar.js

const api = require('/api.js');

/**
 * 切换tab
 * @param me
 * @param index
 */
const switchTab = function (me, index) {
    if (typeof me.getTabBar === 'function' && me.getTabBar()) {
        console.log("切换tab:", index);
        me.getTabBar().setData({
            selected: index
        })
    }
};

/**
 * 显示 tabBar 某一项的右上角的红点
 * @param me
 * @param index
 */
const showRedDot = function (me, index, success, fail) {
    if (typeof me.getTabBar === 'function' && me.getTabBar()) {
        me.getTabBar().showRedDot(index, success, fail);
    }
};

/**
 * 隐藏 tabBar 某一项的右上角的红点
 * @param me
 * @param index
 */
const hideRedDot = function (me, index, success, fail) {
    if (typeof me.getTabBar === 'function' && me.getTabBar()) {
        me.getTabBar().hideRedDot(index, success, fail);
    }
};

/**
 * 显示tab右上角文本
 * @param me
 * @param index
 * @param text
 */
const showBadge = function (me, index, text, success, fail) {
    if (typeof me.getTabBar === 'function' && me.getTabBar()) {
        me.getTabBar().showBadge(index, text, success, fail);
    }
};

/**
 * 隐藏tab右上角文本
 * @param me
 * @param index
 */
const hideBadge = function (me, index, success, fail) {
    if (typeof me.getTabBar === 'function' && me.getTabBar()) {
        me.getTabBar().hideBadge(index, success, fail);
    }
};

/**
 * 显示tabbar
 * @param me
 * @param success
 */
const showTab = function(me, success){
    if (typeof me.getTabBar === 'function' && me.getTabBar()) {
        me.getTabBar().showTab(success);
    }
};

/**
 * 隐藏tabbar
 * @param me
 * @param success
 */
const hideTab = function(me, success){
    if (typeof me.getTabBar === 'function' && me.getTabBar()) {
        me.getTabBar().hideTab(success);
    }
};

module.exports = {
    switchTab, showRedDot, hideRedDot, showBadge, hideBadge, showTab, hideTab
};


最后,进入到tab对应页面的时候要手动调用一下swichTab接口,然tabbar聚焦到当前tab

/**
 * 生命周期函数--监听页面显示
 */
onShow: function () {
    tabbar.switchTab(this, this.data.tabIndex);//tabIndex是当前tab的索引
}
最后一次编辑于  2021-11-09  
点赞 14
收藏
评论

12 个评论

  • 张
    2022-05-24

    楼主,你的tabbar对应的四个页面是写成了自定义组件然后引入到一个页面,再点击切换控制组件显隐的吗

    2022-05-24
    赞同
    回复 1
    • showms
      showms
      2022-05-27
      tabbar是自定义组件,tabbar对应的页面只是引了一个公共的操作tabbar的js
      2022-05-27
      回复
  • 蓝天
    蓝天
    2022-04-21

    必须要在 tabbar list 里面 先声明好,需要调整的tabbar啊,有什么意思,不能完全自定义...

    2022-04-21
    赞同
    回复
  • uxiang
    uxiang
    2021-09-28

    wepy里面要怎么写呀

    2021-09-28
    赞同
    回复
  • 张朝
    张朝
    2021-08-15

    这种在tab 对应组件页面发起分享,怎么回调页面的 onShareAppMessage 事件呢?

    2021-08-15
    赞同
    回复
  • 紫川秀
    紫川秀
    2021-06-25

    试用了楼主的小程序跳转没有闪,可是代码片段试用是闪烁的,楼主怎么优化的呀

    2021-06-25
    赞同
    回复
  • 不二mew
    不二mew
    2021-03-22

    如何隐藏自定义tabbar啊,我只想在三个页面显示,另外的都隐藏

    2021-03-22
    赞同
    回复 1
    • showms
      showms
      2021-12-17
      不想显示的页面设置hideTabBar=true就可以了
      2021-12-17
      回复
  • 幻想国度
    幻想国度
    2020-11-04

    我想请问一下,你js中的ready函数执行几次

    2020-11-04
    赞同
    回复
  • 8&24
    8&24
    2020-07-28

    你页面是直接用了页面形式,而不是组件是吗

    2020-07-28
    赞同
    回复 1
    • showms
      showms
      2020-08-17
      自定义组件
      2020-08-17
      回复
  • 一切安好
    一切安好
    发表于移动端
    2020-05-31
    c
    2020-05-31
    赞同
    回复
  • 默
    2020-05-28

    你好 我想问下

    1.页面切换的时候页面会闪烁吗?

    2.页面切换的时候页面会重新刷新吗?

    能发下代码片段吗,我按照别的例子写的不是刷新页面就是根本不会显示tabbar

    2020-05-28
    赞同
    回复 2
    • showms
      showms
      2020-05-28
      1、你可以打开我的小程序进去看看效果,闪烁的话应该还好,可以接受。主要是进入目标页面后再把对应tab设置成选中状态
      2、官方说 每个 tab 页下的自定义 tabBar 组件实例是不同的 所以切换的时候页面会重新加载
      目前文章里面的代码就是我目前正在用的蛤
      2020-05-28
      回复
    • 默
      2020-05-29回复showms
      看了一下 效果还不错 就是切换的时候tabbar也是会闪烁 但是页面好像看着没有重新加载的样子这个还可以接受
      2020-05-29
      回复

正在加载...

登录 后发表内容