乐趣区

微信小程序自定义tabBar在uniapp的适配

引言:此方法可用作大部分微信小程序支持,但 uni-app 文档中却找不到相关说明的 API

需求

需要在微信小程序中,实现一个中间图标突出显示的异形导航栏。

如下图

实现方法设计

要做这种异形的导航栏,用直接在配置文件里面写 list 的方法肯定做不到。那么,就有以下两种可替代方法。

  1. 在每一个页面都加载一个 tabBar 组件,与页面同时渲染。
  2. 设置自定义 tabBar, 修改 tabBar 的样式。

优缺点分析:方法 1 实现起来略为简单,但是会出现代码可重用率低,降低性能,已经界面跳动等问题。方法 2 则是微信官方提供的,自定义方式,相信在性能方面也会有很大的优势。故选择方法 2。

1. 查看文档及官方 Demo

官方文档

简要描述一下就是需要在根目录中加入一个 custom-tab-bar 目录,里面的文件结构与自定义组件的结构一致。然后再在小程序配置文件中修改 tabbar 为 custom 模式。

官方代码

主要重点为三个部分

  • 配置文件

  • custom-tab-bar 目录

  • 页面生命周期中的设置索引方法

这段代码其实很容易理解,pageLifetimes 就是监听组件所在页面的生命周期。上述代码就是监听页面显示。当页面显示后,获取到 tabBar 的对象,然后再设置 tabBar 中的 index 索引。

2. 迁移到 uni-app 框架

上面的方法是使用微信小程序的开发方式,而我使用的是 uni-app 框架开发微信小程序的。所以我们需要把它们移植到 uni-app 框架内。

  • 配置文件的修改

uni-app 中,page.json 被编译为微信小程序的 app.json。所以,我们直接修改 page.json

  • custom-tab-bar 目录的适配

我们知道,uni-app 使用的是类 Vue 开发,将一个 Vue 文件编译为四个微信页面文件(wxml,wxss,json,js)。那么,是否可以直接写一个 custom-tab-bar.vue 的文件呢?刚开始我也是这么想的,后来发现 uni-app 只会编译 page 目录和 component 目录下的 vue 文件。而微信小程序要求 custom-tab-bar 必须在项目的根目录下。那么就只能在 uni-app 下创建一个 custom-tab-bar 目录,并老老实实写微信四件套了。

写完后,uni-app 会将该目录完美的复制至微信小程序项目的根目录。

  • tab 页面内的适配方法

这个在我实际开发中,是最令我头痛的了。因为微信小程序的 this 引用与 uni-app 的 this 引用并不相同。所以如果直接复制代码是会编译出错的。而另一个问题则是,uni-app 并未提供 pageLifetimes 的事件监听。

在我经过一番摸索之后,发现将设置索引方法写在 onShow 事件里面,效果是等效的。接下来便只剩下 this 的问题了。

如果直接复制的话,会出现无任何效果的情况

因为 uni-app 的 this 引用不一样,所以它在判断 getTabBar 的时候,获取的是“undefined”所以不会执行下面的操作。如果你将判断去掉,则会直接报“undefined”错误。

难道实现不了?其实不然,万变不离其宗。uni-app 也是编译到小程序的,所以绝对有迹可循。

我们首先看看 uni-app 里面 this 的内容。

我们可以很明显的看到里面有个 $mp 的对象,说明这应该是微信小程序专用的对象。接下来我们继续分析$mp

这里面有一个隐藏很深的 getTabBar 方法,我们直接调用它,和在微信小程序里面调用 this.getTabBar 是等效的。

所以我们就可以把 onShow 里面的内容写成这样。

一些优雅点的封装

设置索引方法独立出来

在 methods 对象中,添加

setTabBarIndex(index){
            if (typeof this.$mp.page.getTabBar === 'function' &&
                this.$mp.page.getTabBar()) {this.$mp.page.getTabBar().setData({selected:index})
            }
        }

使用 mixin 避免重复书写复制

main.js 中,添加

Vue.mixin({
    methods:{setTabBarIndex(index){
            if (typeof this.$mp.page.getTabBar === 'function' &&
                this.$mp.page.getTabBar()) {this.$mp.page.getTabBar().setData({selected:index})
            }
        }
    }
})

混入后的使用

在页面文件中

onShow() {this.setTabBarIndex(0) //index 为当前 tab 的索引
        }

over!

退出移动版