«

uniapp怎么自定义tabbar

时间:2024-7-8 14:46     作者:韩俊     分类: Javascript


这篇文章主要讲解了“uniapp怎么自定义tabbar”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“uniapp怎么自定义tabbar”吧!

思路

实现思路就是通过通过自定义view来实现我们这个tabbar功能,然后页面通过组件来展示。通过点击不同的tab来显示不同的组件来达到模拟原生tabbar切换效果。那有些人要问了,你咋知道我项目中有多少个tab,这些tab叫什么名字了?那这里就可以利用uniapp提供的组件easycom模式来解决这些问题,只要我们设置好组件的限制个数和提前占位名称,这些问题就迎刃而解。

实现

1、我们现在components(没有就新建一个components目录)目录下新建一个文件夹(我这里叫ctab),然后分别新建一个vue组件和一个js文件。组件可以让我们在其他地方引用,js文件主要是做配置。

2、新建tab组件,我们组件最多限制5个tab组件,然后需要通过easycom占位来实现,所以你需要几个tab组件就在components目录下建几个组件命名为ctabx。如下所示,我这里要展示三个tab:

特别注意这里的tab组件命名一定要符合easycom规范,不然可能会引起组件引用错误。

这里示例一个ctab1写法:

<template>
    <view >
        首页
    </view>
</template>
<script>
    export default {
        name: "ctab1",
        data() {
            return {};
        },
        mounted() {},
        methods: {}
    }
</script>
<style>
</style>

3、tabbar组件ctab.vue实现,这里就直接上代码了,直接copy就能使用,关键地方已加上注释

<template>
    <view>
        <!--中间按钮凸起模式-->
        <block v-if="midBtn && midBtn.show">
            <!--凸起模式最多展示四个-->
            <block v-if="tabs.length < 4">
                <ctab1 v-show="sindex == 0"></ctab1>
                <ctab2 v-show="sindex == 2"></ctab2>
            </block>
            <block v-else="tabs.length >= 4">
                <ctab1 v-show="sindex == 0"></ctab1>
                <ctab2 v-show="sindex == 1"></ctab2>
                <ctab3 v-show="sindex == 3"></ctab3>
                <ctab4 v-show="sindex == 4"></ctab4>
            </block>
            <view class="tabbar">
                <!--中间按钮凸起模式tab为3个或者5个-->
                <view class="tab-item"
                      v-for="(item,index) in (tabs.length < 4 ? 3 : 5)"
                      :key="item"
                      @click="handleTabClick(index)">
                      <!--中间按钮凸起显示图片和文字-->
                    <block v-if="index == floor">
                        <view :
                                class="mid-btn">
                            <image :src="midBtn.icon"
                                   :
                                   @click="handleMidBtn"/>
                        </view>
                        <text class="mid-text"
                              :
                              v-show="midBtn.showtext">{{midBtn.text}}</text>
                    </block>
                    <!--普通tab这里需要注意index选择-->
                    <block v-else>
                        <view class="c-tab-item">
                            <text :class="'tab-iconfont iconfont '+(tabs[index < floor ? index : index-1].iconfont)"
                                  :
                                  v-if="tabs[index < floor ? index : index-1].iconfont"/>
                            <image :src="sindex == index ? tabs[index < floor ? index : index-1].iconSelect : tabs[index < floor ? index : index-1].icon"
                                   class="tab-icon"
                                   v-else/>
                            <text class="tab-text"
                                  :>{{tabs[index < floor ? index : index-1].text}}</text>
                            <view class="corner"
                                  v-show="tabs[index < floor ? index : index-1].mark > 0">{{tabs[index < floor ? index : index-1].mark > 99 ? '99+' : tabs[index < floor ? index : index-1].mark}}</view>
                        </view>
                    </block>
                </view>
            </view>
        </block>
        <!--普通模式-->
        <block v-else>
            <block v-if="tabs.length == 1">
                <ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
            </block>
            <block v-else-if="tabs.length == 2">
                <ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
                <ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
            </block>
            <block v-else-if="tabs.length == 3">
                <ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
                <ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
                <ctab3 v-show="sindex == 2 && tabs[2].show"></ctab3>
            </block>
            <block v-else-if="tabs.length == 4">
                <ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
                <ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
                <ctab3 v-show="sindex == 2 && tabs[2].show"></ctab3>
                <ctab4 v-show="sindex == 3 && tabs[3].show"></ctab4>
            </block>
            <block v-else-if="tabs.length >= 5">
                <ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
                <ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
                <ctab3 v-show="sindex == 2 && tabs[2].show"></ctab3>
                <ctab4 v-show="sindex == 3 && tabs[3].show"></ctab4>
                <ctab5 v-show="sindex == 4 && tabs[4].show"></ctab5>
            </block>
            <view class="tabbar">
                <view class="tab-item"
                      v-for="(item,index) in tabs"
                      :key="item.text"
                      v-show="item.show"
                      @click="handleTabClick(index)">
                    <view class="c-tab-item">
                        <text :class="'tab-iconfont iconfont '+(item.iconfont)"
                              :
                              v-if="item.iconfont"/>
                        <image :src="sindex == index ? item.iconSelect : item.icon"
                               class="tab-icon"
                               v-else/>
                        <text class="tab-text"
                              :>{{item.text}}</text>
                        <view class="corner"
                              v-show="item.mark > 0">{{item.mark > 99 ? '99+' : item.mark}}</view>
                    </view>
                </view>
            </view>
        </block>
    </view>
</template>

<script>
    //读取配置
    import ctabbar from './ctab-config.js'
    export default {
        name: "ctab",
        data() {
            return {
                tabs: [],
                color: '',
                scolor: '',
                midBtn: {},
                sindex: 0,
                floor: -1,//midButton开启时使用
            }
        },
        mounted() {
            let tabbar = ctabbar.tabbar
            this.color = tabbar.color
            this.scolor = tabbar.selectcolor
            if(tabbar.midButton && tabbar.midButton.show && tabbar.tabs.length < 2){
                throw new Error('midButton模式开启,配置tab选项不能少于2个')
            }
            if(tabbar.midButton && tabbar.midButton.show){
                let mlength = tabbar.tabs.length < 4 ? 3 : 5
                this.floor = Math.floor(mlength/2)
            }
            //普通模式,设置选中的tab项
            let tablen = tabbar.tabs.length
            if(!tabbar.midButton.show){
                if(!tabbar.tabs[0].show){
                    this.sindex ++
                    if(tablen >= 2 && !tabbar.tabs[1].show){
                        this.sindex ++
                        if(tablen >= 3 && !tabbar.tabs[2].show){
                            this.sindex ++
                            if(tablen >= 4 && !tabbar.tabs[3].show){
                                this.sindex ++
                                if(tablen >= 5 && !tabbar.tabs[4].show){
                                    throw new Error('tab不能全部隐藏')
                                }
                            }
                        }
                    }
                }
            }
            if(tabbar.tabs.length <= 5){
                this.tabs = tabbar.tabs
            }else {
                this.tabs = tabbar.tabs.slice(0,5)
            }
            this.midBtn = tabbar.midButton
        },
        methods: {
            setTheme(color){
                this.scolor = color
                this.midBtn.background = color
            },
            //设置tab隐藏和显示,midButton模式失效
            setTabVisible(index,visible){
                if(this.tabs[index]){
                    this.tabs[index].show = visible
                }
            },
            //设置角标
            setCorner(index,num){
                if(this.tabs[index]){
                    this.tabs[index].mark = num
                }
            },
            handleTabClick(tab){
                if(this.midBtn && this.midBtn.show){
                    if(tab == this.floor){
                        return
                    }
                }
                this.sindex = tab
                let rindex = tab
                if(this.midBtn && this.midBtn.show){
                    if(tab > this.floor){
                        rindex --
                    }
                }
                this.$emit('tabClick',rindex)
            },
            handleMidBtn(){
                this.$emit('midClick')
            }
        }
    }
</script>

<style>
    /*这里引入字体图标,如果使用字体图标的话*/
    @import '@/common/font/iconfont.css';
    .tabbar {
        position: fixed;
        z-index: 99;
        width: 100%;
        height: 100rpx;
        background-color: #ffffff;
        bottom: 0;
        left: 0;
        box-shadow: 0rpx 4rpx 8rpx 0rpx rgba(0,0,0,0.5);
        border-radius: 0px 0px 0px 0px;
        opacity: 1;
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: center;
        padding-bottom: constant(safe-area-inset-bottom);
        padding-bottom: env(safe-area-inset-bottom);
        box-sizing: content-box;
    }
    .tab-item {
        flex: 1;
        height: 100rpx;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }
    .c-tab-item {
        height: 120rpx;
        display: flex;
        flex-direction: column;
        width: 120rpx;
        align-items: center;
        justify-content: center;
        position: relative;
    }
    .tab-icon {
        width: 45rpx;
        height: 45rpx;
    }
    .tab-iconfont {
        font-size: 45rpx;
        font-weight: bold;
    }
    .tab-text {
        font-size: 26rpx;
        color: #333333;
        margin-top: 5rpx;
    }
    .mid-btn {
        position: absolute;
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
        background-color: red;
        border-radius: 50%;
    }
    .mid-text {
        font-size: 25rpx;
        color: #999999;
    }
    .corner {
        text-align: center;
        width: 45rpx;
        height: 45rpx;
        position: absolute;
        background-color: red;
        border-radius: 50%;
        color: white;
        font-size: 20rpx;
        font-weight: bold;
        top: 5rpx;
        right: 0;
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
    }
</style>

4、配置文件如下:

var tabbar = {
    /*开启midButton模式时取前两个或者前四个显示,其他忽略*/
    midButton: {
        show: true,//是否是中间凸起模式
        width: '153rpx',//不填默认150rpx 中间按钮大小
        iconwidth: '67rpx',//不填默认150rpx 中间图标大小
        iconheight: '60rpx',
        offset: '40rpx',//不填默认50rpx
        background: '#F7D456',//中间按钮背景颜色
        text: '拍一拍',
        textoffset: '50rpx',//不填默认50rpx
        showtext: false,
        icon: '../../static/tabbar/camera.png'
    },
    color: '#333333',//未选中颜色
    selectcolor: '#F7D456',//选中颜色
    /*tabs最多5个,超过5个超过的部分会被忽略,show属性用来控制tab显示隐藏,midButton开启时失效,iconfont优先,没有就使用icon*/
    tabs: [{
        icon: '../../static/tabbar/main_tab_home_normal.png',
        iconSelect: '../../static/tabbar/main_tab_home_select.png',
        text: '首页',
        iconfont: '',
        show: true,
        mark: 0//角标数量,小于等于0不显示
    }, {
        icon: '../../static/tabbar/main_tab_task_normal.png',
        iconSelect: '../../static/tabbar/main_tab_task_select.png',
        text: '任务',
        iconfont: '',
        show: true,
        mark: 100
    }, {
        icon: '../../static/tabbar/main_tab_my_normal.png',
        iconSelect: '../../static/tabbar/main_tab_my_select.png',
        text: '我的',
        iconfont: 'icon-wode',//注意配置字体图标会优先使用字体图标,这里是示例
        show: true,
        mark: 9
    }]
}

module.exports = {
    tabbar
}

5、使用示例:

<template>
    <ctab @midClick='midClick'
          @tabClick='tabClick'
          ref="ctab"/>
</template>

<script>
    export default {
        data() {
            return {

            }
        },
        onLoad() {

        },
        methods: {
            //凸起按钮点击事件
            midClick(){
                console.log('midClick')
            },
            //tab切换点击事件
            tabClick(tab){
                console.log('tabClick',tab)
            }
        }
    }
</script>

<style>
    page {
        width: 100%;
        height: 100%;
    }

</style>

6、到这里我们自定义tabbar就完成了,通过修改配置文件中的midButton中的show属性来开启是否中间按钮凸起,接下来我们看下效果。
midButton开启:

普通模式:

再普通模式下,我们可以通过配置或者动态修改tabs中tab obj中的show属性来动态形式和隐藏某个tab,我们这里配置第一个tab为隐藏:

...
tabs: [{
        icon: '../../static/tabbar/main_tab_home_normal.png',
        iconSelect: '../../static/tabbar/main_tab_home_select.png',
        text: '首页',
        iconfont: '',
        show: false,//隐藏第一个tab
        mark: 0//角标数量,小于等于0不显示
    }, {
        icon: '../../static/tabbar/main_tab_task_normal.png',
        iconSelect: '../../static/tabbar/main_tab_task_select.png',
        text: '任务',
        iconfont: '',
        show: true,
        mark: 100
    }, {
        icon: '../../static/tabbar/main_tab_my_normal.png',
        iconSelect: '../../static/tabbar/main_tab_my_select.png',
        text: '我的',
        iconfont: '',
        show: true,
        mark: 9
    }]
...

效果图如下:

7、到这里我们的自定义tabbar就完成了,剩下的就是在tab组件中实现我们各个页面的逻辑。我们通过配置文件可以轻松的使用一个套代码实现tabbar中间按钮凸起、数字角标、动态隐藏、自定义mask覆盖tabbar(需要自己控制好层级),字体图标等功能,并且全端适用。

标签: javascript

热门推荐