前言
在开发小程序的时候,一般的小程序用官方自带的菜单栏就够了,但一但稍微复杂的小程序可能因为产品经理的一句“页面太多了得加个菜单”,就可能要对菜单栏进行增、删、改的操作,这个时候自带的就满足不了需求了,可以使用官方提供的自定义菜单栏。但官方提供的自定义菜单栏有个特点,就是菜单栏的页面必须是 Component
,假如你是在项目做到一半的时候有要对菜单栏进行增、删、改的需求,用官方提供自定义菜单栏就需要把page页面改成 Component
,那就需要很多时间修改页面逻辑,会很麻烦。所以这个时候,我们就可以采用官方自带的菜单栏和自己封装的菜单栏组合使用,这样能节省修改逻辑的时间,还能享受自带菜单的良好交互。
思路
我们可以用小程序自带的菜单和我们自己封装的自定义菜单组件使用,具体逻辑是这样的:
- 我们先可以在全局 app.js 文件的全局变量 globalData 里定义一个区分展示自定义菜单还是官方自带菜单的变量
tabbar_type
- 通过
tabbar_type
在每个菜单页面区分展示官方自带的菜单栏还是自己封装的自定义菜单栏 - 当展示自定义菜单栏的时候调用官方提供的 api 隐藏官方自带的菜单栏。当展示官方菜单栏的时候,通过修改全局变量
tabbar_type
的值来隐藏自定义菜单栏
成品效果
具体实现
先在 app.json 页面配置好官方自带的菜单栏
代码语言:javascript复制 "tabBar": {
"custom": false,
"color": "#999999",
"selectedColor": "#00C3B3",
"borderStyle": "black",
"backgroundColor": "#f8f8f8",
"list": [
{
"selectedIconPath": "/assets/img/homeActive.png",
"iconPath": "/assets/img/home.png",
"pagePath": "pages/index/index",
"text": "首页"
},
{
"selectedIconPath": "/assets/img/mallActive.png",
"iconPath": "/assets/img/mall.png",
"pagePath": "pages/index/index",
"text": "商城"
},
{
"selectedIconPath": "/assets/img/myActive.png",
"iconPath": "/assets/img/my.png",
"pagePath": "pages/index/index",
"text": "我的"
}
]
},
然后封装一个自定义的菜单栏组件目录结构:
代码语言:javascript复制 components
shoping-tabbar
- index.js
- index.json
- index.wxml
- index.wxss
index.js 文件代码
代码语言:javascript复制// components/shoping-tabbar/index.js
const app = getApp();
Component({
/**
* 组件的属性列表
*/
properties: {
selected: {
type: Number,
default: 0
}
},
/**
* 组件的初始数据
*/
data: {
selectedIndex: 0,
color: "#999999",
selectedColor: "#00C3B3",
list: [
{
"selectedIconPath": "/assets/img/mallActive.png",
"iconPath": "/assets/img/mall.png",
"pagePath": "/pages/index/index",
"text": "商城"
},
{
"selectedIconPath": "/assets/img/cartActive.png",
"iconPath": "/assets/img/cart.png",
"pagePath": "/pages/index/index",
"text": "购物车"
},
{
"selectedIconPath": "/assets/img/orderActive.png",
"iconPath": "/assets/img/order.png",
"pagePath": "/pages/index/index",
"text": "订单"
}
]
},
attached: function () {
this.setData({
selectedIndex: this.properties.selected
})
},
/**
* 组件的方法列表
*/
methods: {
switchTab(e) {
let data = e.currentTarget.dataset
let url = data.path
wx.redirectTo({
url,
fail: function (err) {
wx.switchTab({
url
})
},
success: () => {
this.setData({
selectedIndex: data.index
})
}
})
wx.hideTabBar({
animation: false,
success: () => {
app.globalData.tabbar_type = 2
}
})
}
},
})
index.wxml 文件
代码语言:javascript复制<view class="tab-bar">
<view class="tab-bar-border"></view>
<view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
<image src="{{selectedIndex === index ? item.selectedIconPath : item.iconPath}}"></image>
<view style="color: {{selectedIndex === index ? selectedColor : color}}">{{item.text}}</view>
</view>
</view>
然后在需要自定义菜单组件的页面引入selected 为菜单的序号,比如成品效果动态图中的自定义菜单分别有商城、购物车、订单三个页面,序号分别为1,2,3。
代码语言:javascript复制<nav-tabar selected="{{selected}}" wx:if="{{tabbar_type==2}}"></nav-tabar>
然后在自定义菜单栏页面(商城、购物车、订单)的 onShow()
方法里分别初始化是否显示菜单的变量
this.setData({
tabbar_type: app.globalData.tabbar_type
})
最后一步很关键,通过上面的成品效果动态图可以看到,从官方自带的菜单栏跳我们封装的自定义菜单栏的页面,是通过 商城 这个页面中转的,这个页面比较特别,它既是官方自带的菜单中的一个页面,又用了我们自己封装的自定义菜单栏组件。我们可以通过官方提供的 onTabItemTap()
来监听,当展示官方菜单栏且点击这个tab页的时候就隐藏官方的菜单栏,展示自己封装的自定义菜单栏。
/**
* 当前是 tab 页时,点击 tab 时触发
* @param {*} item
*/
onTabItemTap(item) {
wx.hideTabBar({
animation: false,
success: () => {
this.setData({
tabbar_type: 2
})
app.globalData.tabbar_type = 2
}
})
},
然后在这个中转页商城页的返回事件这样处理:隐藏自己封装的菜单栏,展示官方的菜单栏
代码语言:javascript复制 navToBack() {
let pages = getCurrentPages();
// 获取前一个页面的路径
let prevpageHtml = pages[0].__displayReporter.showReferpagepath;
wx.showTabBar({
animation: true,
success: () => {
wx.switchTab({
url: `/${prevpageHtml.substring(0, prevpageHtml.lastIndexOf('.html'))}`,
})
this.setData({
tabbar_type: 1
})
app.globalData.tabbar_type = 1;
}
})
},
总结
用官方自带的菜单栏和自己封装的自定义菜单栏组合使用的好处就是既能享受官方自带菜单栏的友好交互,有能把中途因需求原因改菜单栏需将 tabbar页 从 page 改成 component 的时间省下。这样的骚操作在这种情况还是很可行的,哈哈。话说时间过得真快呀,再过35分钟就是下半年的第一天了,祝大家都有个好的下半场开端吧!