uniapp自定义tabber

2,247 阅读3分钟

uniapp自定义tabber

注:因为项目是老代码,我不想改动太大,所以用的自定义这种自定义tabber方法,第一次会出现点击的时候图标闪烁问题,目前先使用展位图片。如果想要更好的解决建议把tabBar和页面组件都放在单页中用v-if判断,进行切换,单页切换的缺点是不能进行路由跳转

效果

图片随便找的所以样式有些不好看
pc端: image.png

image.png

image.png

image.png

image.png

小程序端

image.png

image.png

image.png

解析

小程序底部tabber是可以动态配置的,看了下方法可以改,页面写好了,准备处理小程序的时候发现,uniapp 本身的动态设置tabbar方法 uni.setTabBarItem(OBJECT),好像没办法修改个数和修改跳转路径。

uni.setTabBarItem(OBJECT)

uni.setTabBarItem是uni-app框架中用于动态设置原生底部tabbar组件中的某一项的方法

uni.setTabBarItem({
  index: Number,
  text: String,
  iconPath: String,
  selectedIconPath: String
});
  • index:Number类型,必选项,表示要修改的tab的下标,从0开始编号。
  • text:String类型,可选项,表示要修改的tab的文本内容。
  • iconPath:String类型,可选项,表示要修改的tab的图片路径,路径格式和大小限制参考uni-app官方文档。
  • selectedIconPath:String类型,可选项,表示要修改的tab被选中时的图片路径,路径格式和大小限制参考uni-app官方文档

image.png

问题:
1.修改pagePath不跳转。
用这个方法改完后,发现点击时取的是pages.jsontabBarlist的数据。
2.无法修改tabber个数。
UniApp 中的 uni.setTabBarItem 方法用于设置修改底部 TabBar 菜单栏的图标、文字等属性,但是该方法并不能直接用于修改 TabBar 的个数。修改 pages.json 文件中的 tabBar.list 属性,添加或删除需要的 TabBar 项,即可实现修改 TabBar 的个数。(在修改 pages.json 文件中的 tabBar.list 属性之后,可能需要重新编译小程序才能生效)
3.动态配置底部tabber三种展示方式。图文/图标/文字。
设置图标为空后,图标位置空白,样式没有修改,只展示了文字。

自定义tabber

在App.vue页面中

    //隐藏tabber
    onLaunch: function(options) {
        uni.hideTabBar()
    }
 async created() {
     //请求数据
    await this.getAppNav();
  },
  methods:{
   getAppNav(){
      ···请求内容
      arr 为请求数据
      uni.setStorageSync('tabber', arr)
    }
  }
 

写一个tabber组件

需求:动态配置底部tabber。
根据后台配置展示图文/图标/文字的底部tabber的类型
地址,跳转路径,图片都可以配置

<template>
    <view v-if="show" class="tabbar-container">
        <view
            :class="currentIndex === item.index ? 'tabbar-item is-active' : 'tabbar-item'"
            v-for="(item, index) in list"
            :key="index"
            @click="switchTab(item)"
        >
            <image
                v-if="type != 3"
                class="tabbar-icon"
                :src="currentIndex === item.index ? item.selectedIconPath : item.iconPath"
            />
            <view v-if="type != 2" :class="currentIndex === item.index ? 'tabbar-text is-active' : 'tabbar-text'">{{
                item.text
            }}</view>
        </view>
    </view>
</template>

<script>
const http = require('@/utils/http.js')
const config = require('@/utils/config.js')
export default {
    data() {
        return {
            // 当前选中的tabbar菜单索引
            currentIndex: 0,
            list: [],
            type: 1,
            paddingBottomHeight: 0,
            show:true,
        }
    },
    created() {
      let that = this;
      uni.getSystemInfo({
          success: function(res) {
              let model = ['X', 'XR', 'XS', '11', '12', '13', '14', '15'];
              model.forEach(item => {
                //适配iphoneX以上的底部,给tabbar一定高度的padding-bottom
                if (res.model.indexOf(item) != -1 && res.model.indexOf('iPhone') != -1) {
                    that.paddingBottomHeight = 40;
                }
              })
          }
        });
        let selectedIndex = uni.getStorageSync('selectedIndex')
        that.currentIndex = selectedIndex || 0
        const list = uni.getStorageSync('tabber')
        if (!!list) {
            that.list = list
        } else {
            that.getAppNav()
        }
    },
    methods: {
        getAppNav() {
            http.request({
                url: `/appNav/list`,
                method: 'GET',
                callBack: (res) => {
                    let arr = []
                    if (res.length) {
                        this.type = res[0].type
                        const shopId = uni.getStorageSync('shopId')
                        uni.setStorageSync('appNavList', res)
                        let picDomain = config.picDomain
                        res.forEach((v, i) => {
                            let img = v.pic.split(',')
                            let item
                            let text = v.type !== 2 ? v.title : ''
                            let index = i
                            let pagePath = v.path
                            let path = v.path
                            // linkType // 1商品详情(暂时弃用)  2购物车 2个人中心 4自定义路径 5微页面
                            if (v.linkType == 5) {
                                path = 'pages/feature-index/feature-index0'
                                pagePath = `pages/feature-index/feature-index0?renovationId=${v.path}&shopId=${shopId}`
                            }
                            let obj = {
                                path,
                                linkType: v.linkType,
                                pagePath,
                                index,
                            }
                            if (v.type == 2) {
                                item = {
                                    ...obj,
                                    iconPath: picDomain + img[0],
                                    selectedIconPath: picDomain + img[1],
                                    text,
                                }
                            } else if (v.type == 1) {
                                item = {
                                    ...obj,
                                    text,
                                    iconPath: picDomain + img[0],
                                    selectedIconPath: picDomain + img[1],
                                }
                            } else {
                                item = {
                                    ...obj,
                                    text,
                                    iconPath: '',
                                    selectedIconPath: '',
                                }
                            }
                            arr.push(item)
                        })
                        this.list = arr
                          // 获取当前页面实例对象
                        const pages = getCurrentPages();
                        const currentPage = pages[pages.length - 1];
                        // 获取当前页面路径
                        const currentPath = currentPage.route; // 或者使用 currentPage.$page.fullPath 获取全路径
                        const item = arr.filter((v) => currentPath == v.path)
                        console.log(item,'itme')
                        this.show = item.length>0 ? true:false,
                        uni.setStorageSync('tabber', arr)
                    }
                },
            })
        },
        /**
         * @description: 切换
         * @param {*} item
         */
        switchTab(item) {
            let url = '/' + item.pagePath
            // uni.switchTab 方法只能用于跳转 TabBar 页面,无法跳转非 TabBar 页面
            if (item.linkType == 5) {
                uni.reLaunch({ url })
            } else {
                uni.switchTab({ url })
            }
            // uni.navigateTo({url})
            this.list.forEach((v) => {
                if (item.pagePath === v.pagePath) {
                    uni.setStorageSync('selectedIndex', item.index)
                }
            })
        },
    },
}
</script>

<style lang="css" scoped>
.tabbar-container {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 50px;
    background: #fff;
    border-top: 1px solid #dedede;
    display: flex;
    justify-content: space-around;
    z-index: 9999;
}
.tabbar-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    padding-top: 3px;
    color: #999;
}
.tabbar-text {
    font-size: 12px;
    margin-top: 2px;
    color: #333;
}
.tabbar-icon {
    width: 24px;
    height: 24px;
}
/* .tabbar-text {
    color: #07c160;
} */
.is-active {
    color: #07c160;
}
</style>


在tabber组件里判断是否获取tabber数据,没有就获取有就再次请求,因为在操作中,我发现第一次拿不到app.vue缓存的数据,判断没有数据就再次请求一次。苹果还需要设置底部距离。

注册

main.js文件中引入tabber组件

    import tabBar from './components/tabber'
    Vue.component('tab-bar', tabBar)

使用

在需要用的页面直接引入即可

//index页面
  <template>
     <view>
     <view>首页</view>
      <tab-bar></tab-bar>
     </view>
  </template>

注:uni.switchTab 方法只能用于跳转 TabBar 页面,无法跳转非 TabBar 页面