最近开发又涉及到了微信小程序,好多年没写过小程序了
现在要设计一个自定义tabBar
,本来想写成一个页面,子页面都写成组件,但是这样就会损失页面的许多特性,比如生命周期等等
后面了解了下 wx 的 tabBar 原理,其实每个tab页面
(就是底部带 tabBar 的页面,可以通过 wx.switchTab()
访问,这里和普通的页面加以区分),底部的 tabBar 都是单独的
什么意思?也就是说,多个tab页面
底部的tabBar不是通用的,tabBar 是该页面的组件,是一部分,tab页面
可以通过 this.getTabBar()
获取属于自己的 tabBar
当你使用自定义tabBar
的时候,tab 页面就会自动带上这个组件,当然自定义tabBar
是必须由你自己完成实现
看了一些其他人的实现,感觉有点啰嗦,设计的也不完美
这里整合一下我写的,步骤也简单,两个步骤:
步骤一
app.json 中配置好,主要是配置两个
page 这里必须写上
tabBar.custom
为true,这个表面是自定义的 tabBar
tabBar.list
把所有的 tab页面
都列在这,注意前面没''。这必须写,系统会解析处理,这样就可以通过 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",
"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"
}
]
}
}
步骤二
和 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>