小程序自定义tabbar

索嘉胜
2023-12-01

一、官方tabbar

官方文档:https://developers.weixin.qq.com/miniprogram/dev/extended/weui/tabbar.html

1、tabbar配置

  • 在app.json里的 tabBar 字段里配置tabbar页面,只有tabbar页面才能显示底部的tabbar。

2、展示层级

  • tabbar的展示层级最高,且不占用展示区域,页面展示区域在tabbar之上,比如fixed定位、webview页面等都处在tabbar上面的区域,和tabbar不会相互影响。

3、switchTab

  • switchTab 会关闭其他非tabbar页,但tabbar页不会关闭,那么tabbar页的webview类型h5访问地址就不会改变,该tabbar页不会触发onLoad,如需改变需要换用reLaunch。

4、动态修改tabbar

  • 修改tabbar的内容使用wx.setTabBarItem(),但是只能修改tabbar上的文字内容、图标,无法修改链接路径。
  • 修改tabbar的样式使用wx.setTabBarStyle(),但是只能修改tabbar的背景色、文字颜色、上边框颜色。
  • 小程序刚启动时还是会先展示 app.json里配置的默认tabbar,如果动态修改了tabbar,会能看到tabbar改变的过程,手机性能越慢看的越明显,用户体验一般。
  • 修改tabbar的相关api只能在tabbar页面才能使用,且reLaunch会重置tabbar数据为app.json的默认配置。

二、自定义tabbar

官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html

1、介绍

  • 两种方式:一种采用官方自定义tabbar的方式,但是官方的自定义tabbar实际上也存在不少bug,比如某些情况下真机显示了两层。一种完全自己去实现,其实就是用fixed定位写一个,但是在页面切换的时候会有闪动的问题,因为不同的页面都要引入自定义tabbar这个组件,微信小程序里不同页面的组件并不会完全共用。(猜测官方自定义tabbar和自己自定义的基本方式应该是一样的)

2、配置使用

  • 官方自定义tabbar配置方式:在app.json中的tabBar字段里配置custom字段值为true,在代码根目录添加custom-tab-bar组件文件。
  • 建议使用 cover-view + cover-image 组件来写tabbar,以保证更高的展示层级。

三、动态设置官方tabbar

  • 如上所述,官方tabbar的动态设置有很多局限性,不能动态设置tabbar数量,不能动态设置tabbar项的路径;
  • 可以动态设置某个tabbar项的图标文字,如果该项是webview内嵌h5页,那就可以动态设置它的h5地址。
  • 但是使用setTabBarItem这个api也有一些坑,一是在非tabbar页无法使用,二是使用wx.reLaunch()会重置tabbar为默认配置,所以需要做一些处理。

以下是处理方式:

1、封装tabbar.js

/**
 * tabbar动态设置功能封装
 * 
 * 需要在所有tabbar页的 onShow 方法里调用一下 updateBarItemAll()方法
 */

/**
 * tabbar原始配置
 * 和app.json保持一致
 * icon图片需使用网络地址
 */
const originData = [
  {
    "pagePath": "pages/index/index",
    "iconPath": "https://static.com/tabbar/home.png",
    "selectedIconPath": "https://static.com/tabbar/home_selected.png",
    "text": "首页"
  },
  {
    "pagePath": "pages/wo/wo",
    "iconPath": "https://static..com/tabbar/wo.png",
    "selectedIconPath": "https://static.com/tabbar/wo_selected.png",
    "text": "我的"
  }
]

export default {
  originData,
  latestData,

  // 单例模式获取数据
  getTabbarData () {
    if (!this.latestData) {
      this.latestData = JSON.parse(JSON.stringify(originData))
    }
    return this.latestData
  },

  /**
   * 动态设置单项tabbar的图标文案
   */
  setBarItem ({ index, text, iconPath, selectedIconPath, }) {
  	const item = { text, iconPath, selectedIconPath, }
  	
  	// 更新tabbarData单例
    const tabbarData = this.getTabbarData()
    tabbarData[index].text = item.text
    tabbarData[index].iconPath= item.iconPath
    tabbarData[index].selectedIconPath= item.selectedIconPath
    
    // 只在当前为tabbar页时才应用修改
    const isTabbar = this.isInTabbarPage()
    if (isTabbar) {
      this.updateBarItem(index, item)
    }
  },

  /**
   * 更新所有tabbar项
   */
   updateBarItemAll () {
    const tabbarData = this.getTabbarData()
    tabbarData.forEach((v, i) => {
      this.updateBarItem(i, v)
    })
  },

  /**
   * 更新单项tabbar
   */
   updateBarItem (index, item) {
    wx.setTabBarItem({
      index: index,
      text: item.text,
      iconPath: item.iconPath,
      selectedIconPath: item.selectedIconPath,
    })
  },

  /**
   * 判断是否是tabbar页面
   */
  isInTabbarPage (path) {
    const tabbarData = this.getTabbarData()
    const tabbarRoutes = tabbarData.map(v => v.pagePath)
    if (!path) {
      const currentPages = getCurrentPages()
      const page = currentPages[currentPages.length - 1]
      if (!page) {
        return true
      } else {
        path = page.route
      }
    }
    if (path.match(/^\//)) {
      path = path.slice(1)
    }
    const isIn = tabbarRoutes.indexOf(path) > -1
    return isIn
  },
}

2、使用方式

  • 在需要动态修改tabbar的地方不要直接使用官方的wx.setTabBarItem(),而是引用前面封装的tabbar.js,然后调用封装的setBarItem方法。
  • 在所有tabbar页的onShow()生命周期里都调用一下封装的updateBarItemAll方法,用于把最新的tabbar数据应用修改上,因为在非tabbar页调用setBarItem时只是修改了实例latestData而没有应用tabbar的数据修改,并且能保证在使用了wx.reLaunch后也能及时应用上最新的tabbar数据。

3、优化建议

  • 上述封装的是设置指定某一下标的tabbar项,后续可以考虑对setBarItem做个封装修改,支持通过类型来指定设置某一tabbar,比如指定设置“我的”这一项,这样在tabbar后续调整顺序时就不需要修改index参数。

  • 还可以对wx.setTabBarStyle也做个类似的封装,以支持部分样式的动态修改,这里不再赘述了。

 类似资料: