但是引入组件库之后,又会导致一些其他问题,就拿tabbar来说,原生的tabbar,只需要在app.json文件里定义好tabbar的配置,然后在具体的page里写逻辑就好了,框架会自动判断当前tab页并渲染,然后执行对应page的逻辑代码,如下:
"tabBar": {
"list": [{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "./icons/home.png",
"selectedIconPath": "./icons/home-fill.png"
},
{
"pagePath": "pages/create/create",
"text": "创建活动",
"iconPath": "./icons/create.png",
"selectedIconPath": "./icons/creating.png"
}]
}
但是引入三方组件库的 tabbar,就相当于使用了自定义组件,而小程序对自定义 tabbar 的支持并友好,比如切换tab的焦点page的渲染这种基础能力都不提供,实在是无力吐槽。
你可能会说不是有 wx.switchTab()
方法吗,在 onChange(event)
监听事件里设置一下 url 不就好了?但是奇葩的是,在自定义 tabbar 里,每次 switchTab 后,活动的 page 和 event 里的页面索引是不一致的。为了解决这个问题,花了我不少时间,下面贴一下我各种搜索+调试出的解决方法。
先上效果图:
代码在GitHub上都有,所以文章中略过。代码传送门
step1:
在 pages 同级目录新增 custom-tab-bar 目录,以及配套的四个文件(js、json、wxml、wxss),然后在 app.json 里配置默认值,其实就和自定义组件很像,只不过这里对于自定义 tabbar 有很多硬性要求,比如目录名称、所在路径和配置项(都必须一致!)。详见官方文档
step2:
引入组件库,引入方法在vant 文档都写的很清楚了 vant传送门
step3:
关键部分是引入组件库后 custom-tab-bar/index.js
的内容,这里代码还是要贴出来讲一下的:
Page({
data: { // 初始化
active: 'home',
createIcon: 'add-o',
tabs: {
home: "/pages/home/home",
create: "/pages/create/create",
square: "/pages/square/square",
mine: "/pages/mine/mine"
}
},
onChange(event) {
wx.switchTab({
url: this.data.tabs[event.detail]
})
}
});
首先是 data 部分:
- active 是 vant 组件库对 tab 的索引名(和官方自定义 tabbar 的 index 一样的含义,用于确定唯一的 tab),默认是 number,0123这种,因为我用的 name 索引方式,所以这里是string类型
- createIcon 是为了动态修改创建活动 tab 的图标,提取出来的变量,在渲染 tab 的时候会一起改掉
- tabs 是每个tab页跳转的路由
- onChange 方法是在
custom-tab-bar/index.wxml
里绑定的监听事件,当切换tab的时候会触发 - event.detail 就是触发的时候的 tab 索引名,这里用来找到对应的 pagePath,进行跳转
step4:
在每一个 page 页面的 onShow() 事件,通过 setData() 方法设置 tab 索引,如果有别的data属性,比如这里的 create 页面要修改图标,也可以一起赋值。
Page({
data: {},
onShow: function () {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({
active: 'create',
createIcon: 'edit'
})
}
}
});
总结:
这个关键在于,抛弃原有在 onChange 里直接设置 active 属性的方式,因为和 switchTab 切换 tab 会冲突,导致索引被重置。而通过监听 tab 展示事件,利用事件执行的先后顺序,来设置 active 属性。
后记:
tab页面在第一次加载的时候,并不是流畅,后面看如何解决。