菜鸟读文档-Vant Weapp-7(自定义tabbar栏完全指南)

655 阅读4分钟

正文

经过五篇文章的学习, 我们已经基本上了解了实现自定义 tabbar 所需的全部知识. 现在, 让我们一起来编写可能是最好的自定义 tabbar 吧:)

1. 在 app.json 中进行 tabbar 相关设置

"tabBar": {
  "custom": true,
  "color": "#000000",
  "selectedColor": "#000000",
  "backgroundColor": "#000000",
  "list": [{
    "pagePath": "pages/page1/page1",
    "text": "第一页"
  }, {
    "pagePath": "pages/page2/page2",
    "text": "第二页"
  }, {
    "pagePath": "pages/page3/page3",
    "text": "第三页"
  }]
}

2. 编写 custom-tab-bar 文件夹下文件

这个文件夹下的文件将会接管 tabbar 栏的渲染

我们在这里对 vant-weapp 提供的 tabbar 组件进行二次封装(过了这么多期终于回到 vant-weapp 了...)

  • index.json

    {
      "component": true,
      "usingComponents": {
        "van-tabbar": "@vant/weapp/tabbar/index",
        "van-tabbar-item": "@vant/weapp/tabbar-item/index"
      }
    }
    
  • index.wxml

    <van-tabbar active="{{ active }}" bind:change="onChange">
      <block wx:for="{{ list }}" wx:key="text">
        <van-tabbar-item icon="{{ item.icon }}">{{ item.text }}</van-tabbar-item>
      </block>
    </van-tabbar>
    
  • index.js

    Component({
      data: {
        // tabbar 需要的所有数据
        // 注意 pagePath 路径前的 /, 在 app.json 中是不需要加的
        list: [{
          pagePath: "/pages/page1/page1",
          text: "第一页",
          icon: "home-o"
        }, {
          pagePath: "/pages/page2/page2",
          text: "第二页",
          icon: "search"
        }, {
          pagePath: "/pages/page3/page3",
          text: "第三页",
          icon: "star-o"
        }],
        // 当前活跃的 tabbar 子项, 注意初始值为 null
        active: null,
      },
    
      methods: {
        onChange: function(event) {
          // event.detail 的值为当前选中项的索引
          const nextIndex = event.detail;
          // 只需要跳转, 设置 tabbar 子项活跃相关操作于目标页进行
          wx.switchTab({
            url: this.data.list[nextIndex].pagePath
          });
        }
      }
    });
    

3. 在对应页面编写跳转激活

要在对应页面中实现 tab 选中态, 关键就在于在页面的哪一生命周期对自定义 tabbar 进行设置.

微信小程序文档中的样例选择是在 Component 构造器构造页面的 show 生命周期进行设置. 在第6期文章中我们曾进行过相关实验, 根据实验结果, 我个人并不是很喜欢在页面中使用组件生命周期. 而结合第5期文章的实验, 除了首页的自定义 tabbar, 其它页面的自定义 tabbar 其实是在整个页面加载之前就已经加载完成了, 因此, 我们只需要分析首页的自定义 tabbar

我们再次请出在第5期文章中, 整个程序首页生命周期的实验总结图

由于组件的初始化一般是在其本身的 attached 周期, 但是由于从自定义 tabbar 的角度, 我们无法知道当前页面到底是哪一页, 因此, 我们选择在自定义 tabbar 完成渲染之前, 于对应页面处使用 this.getTabBar() 实现对应 tab 的响应态更新

而自定义 tabbar 完成渲染之前的页面生命周期有 onLoadonShow 可以选择, 个人更倾向于在 onLoad 生命周期使用 this.getTabBar(), 因为从第5期文章中对自定义 tabbar 的测试中可以看出: tab 页的 webViewId 和该页的 tabbarwebViewId 是对应的, 即虽然各个 tab 页下的 tabbar 彼此之间是相互独立的, 但某一 tab 页和该页的 tabbar 是相互唯一对应的, 因此我们只需要在该 tab 页载入时, 在 onLoad 生命周期进行一次自定义 tabbar 选中态的设置即可

但是, 阅读了第5期文章的同学也一定知道, 微信小程序的自定义 tabbar 是存在一些问题的. 而如果我们选择将 this.getTabBar() 放在 onShow 生命周期, 不像 onLoad 生命周期只在页面载入时触发一次, onShow 生命周期只要页面出现在用户屏幕上就会触发, 在此生命周期使用 this.getTabBar() 进行选中态数据设置, 由于涉及到 setData(), 下方的 tabbar 将重新被渲染, 这就保证了当页面出现在用户屏幕上时, tab 的选中态一定是正确的

但是如果使用 onShow 生命周期, 用户每选中一个 tab 页, 下方的 tabbar 一定会重新渲染, 这样的又会造成性能损失...

总而言之, 两种选择都无法达到最好的效果, 如果大家有更好的想法, 欢迎分享:)

methods: {
  // onLoad: function () {
  //   if (typeof this.getTabBar === 'function' &&
  //   this.getTabBar()) {
  //   // 在此处设置
  //     this.getTabBar().setData({
  //       active: CURRENT_ACTIVE_TABBAR
  //     })
  //   }
  // }

  onShow: function () {
    if (typeof this.getTabBar === 'function' &&
    this.getTabBar()) {
    // 在此处设置
      this.getTabBar().setData({
        active: CURRENT_ACTIVE_TABBAR
      })
    }
  }
}

最终效果

在编写完上述代码后, 得到的最终效果如下图所示:

预告

组件和弹性布局

到这期为止, 我们的自定义 tabbar 之旅就告一段落啦, 虽然没能够得到最完美的解决方法, 但随着我们的不断学习, 更好的解决办法就一定会出现(只要不停下来, 道路就会不断延伸)

在下一期中, 我们将来到小程序页面部分, 探究在使用组件的前提下, 如何实践弹性布局