微信小程序 自定义 tabBar
最近开发又涉及到了微信小程序,好多年没写过小程序了。
微信小程序一般分为页面、组件,各自有各自的特点,生命周期也不相同
现在要设计一个自定义的 tabBar,本来想写成一个页面,子页面都写成组件,但是这样就会损失页面的许多特性,比如生命周期等等
后面了解了下微信小程序的 tabBar ,发现微信小程序应该分为三种:tab页面、页面、组件
tab页面
是啥?就是底部带 tabBar 的页面,只要按照微信小程序的配置,页面就能自动带上 tabBar,我称之为tab页面
底部的 tabBar 看起来只有一个?错
其实tab页面
底部的 tabBar,就是一个组件,有多少个 tab页面
就有多少个 tabBar!(每个tab页面
可以通过wx.getTabBar()
访问自己的 tabBar 实例)
按照微信小程序你可以弄个简单的tabBar,但是它是固定的,设置有多少个,底部就显示多少个,数量也有限制。但是可以自己做个自己的tabBar(微信小程序官网)
搜索了一些其他人的实现,感觉有点啰嗦,设计的也不完美
这里整合一下我写的,步骤也简单,两个步骤:
步骤一
按照原始的tabBar 配置,修改文件:/app.json
page 这里必须写上
tabBar.custom
为true,这个表面是自定义的 tabBar
tabBar.list
把所有的 tab页面
都列在这,自定义的只需要pagePath 注意前面没''。
系统会根据以上配置进行解析处理,这样就可以通过 wx.switchTab
跳转到 tab页面
了, page就会自动带上自定义tabBar
{
"pages": [
"pages/index1/index1",
"pages/index2/index2",
"pages/index3/index3",
"pages/index4/index4"
],
"tabBar": {
"custom": true,
"list": [
{
"pagePath": "pages/index1/index1"
},
{
"pagePath": "pages/index2/index2"
},
{
"pagePath": "pages/index3/index3"
},
{
"pagePath": "pages/index4/index4"
}
]
}
}
步骤二
和 pages 文件夹并列,建立文件夹custom-tab-bar
,里面命名为 index的组件,里面我还额外建立了一个文件customTabBar.ts
(使用 js 用 js 命名就可以了),以下是各个文件的代码:
代码
customTabBar.ts
// tabBar的data
export const tabBarData: {
listIndex: number,// 底部高亮下标
color: string,
selectedColor: string,
backgroundColor: string,
list: Array<{
pagePath: string,
iconPath: string,
selectedIconPath: string,
text: string,
}>
} = {
listIndex: 0,
color: "#5F5F5F",
selectedColor: "#07c160",
backgroundColor: "#F7F7F7",
list: []
}
// 微信的setData貌似不会对原有的对象进行处理,直接引用上面的tabBarData
// 我舍弃了下面这个方法,毕竟会有一丢丢的性能损失?
// export const getTabBarData = () => JSON.parse(JSON.stringify(tabBarData));
// 所有的list,和 app.json 保持一致
const list = [
{
"pagePath": "pages/index1/index1",
"iconPath": "/assets/首页.png",
"selectedIconPath": "/assets/首页-active.png",
"text": "按钮1"
},
{
"pagePath": "pages/index2/index2",
"iconPath": "/assets/首页.png",
"selectedIconPath": "/assets/首页-active.png",
"text": "按钮2"
},
{
"pagePath": "pages/index3/index3",
"iconPath": "/assets/首页.png",
"selectedIconPath": "/assets/首页-active.png",
"text": "按钮3"
},
{
"pagePath": "pages/index4/index4",
"iconPath": "/assets/首页.png",
"selectedIconPath": "/assets/首页-active.png",
"text": "按钮4"
}
]
// 根据角色设置合适的 list,并更新 tabBarData
// 注意每个 tab 页面,都有自己的独立的 tabbar 组件
// 注意每次设置后都要 wx.relaunch,清空页面缓存
export const setCustomTabBarByRole = (role: 'member' | 'tourist', defaultIndex = 0) => {
tabBarData.listIndex = defaultIndex;
if (role === 'member') {
tabBarData.list = list.slice();
} else if (role === 'tourist') {
tabBarData.list = list.slice(0,3);
}
}
export const changeCustomTabBarIndex = (index: number) => {
const targetNav = tabBarData.list[index];
if (targetNav) {
tabBarData.listIndex = index;
const { pagePath } = targetNav;
wx.switchTab({
// 注意这里路径要加上 '/',而 app.json 不能加上 '/',会报错!
url: '/' + pagePath
})
}
}
index.less
/* custom-tab-bar/index.wxss */
.tabBar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 48px;
background: white;
display: flex;
padding-bottom: env(safe-area-inset-bottom);
border-top: 1px solid #c1c1c1;
}
.tabBarItem {
flex: 1;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.itemImage {
width: 26px;
height: 26px;
}
.itemTitle {
font-size: 10px;
}
index.ts
// custom-tab-bar/index.ts
import { tabBarData, changeCustomTabBarIndex } from "./customTabBar";
Component({
attached() {
// 经过实验,微信小程序页面、组件,data只支持字面量初始化,不支持函数初始化
// 所以在这个时机进行初始化data!
// 注意 setData函数 不会对参数造成影响,所以这里直接放入tabBarData
// 而不是通过 JSON.parse(JSON.stringify(obj)) 复制一份
this.setData(tabBarData);
},
methods: {
switchTab(event: any) {
const { index } = event.currentTarget.dataset;
changeCustomTabBarIndex(index);
},
}
})
index.wxml
<!--custom-tab-bar/index.wxml-->
<view class="tabBar">
<view class="tabBarItem" wx:for="{{list}}" wx:key="index" data-index="{{index}}" bindtap="switchTab">
<image class="itemImage" src="{{listIndex === index ? item.selectedIconPath : item.iconPath}}"></image>
<view class="itemTitle" style="color: {{listIndex === index ? selectedColor : color}}">{{item.text}}</view>
</view>
</view>
效果
注意设置设置底部菜单的时候,要 wx.relaunch()
,这样才可以清除缓存的影响,因为 tab 页面
是会缓存的
其他
可以不清除缓存,直接设置吗?可以
但我没实现(因为不需要),我这里实际上每个 tabBar 实例,只设置了一次data,后续就没管了
而且,tabBar 实例应该和页面路径相匹配,我这里匹配不了,因为只有页面才有资格获取路径
如何实现呢?讲讲方式,因为每个 tabBar 实例,并不能够获取当前页面路径。只有页面才能够获取
所以设置 tabBar 实例的时候,可以通过页面来设置,前面讲到只要是 tab页面
,tab页面
可以通过wx.getTabBar()
获取属于它的 tabBar 实例
每次点击这个页面的时候(也就是 onShow 的时候),就动态设置tabBar的值,参考这个同学