背景
微信小程式提供的原生 tab-bar 功能簡單,樣式單一,無法滿足業務需求。
項目中使用的是 wepy 1.x 架構,實作原理與原生類似。
方案
一、 使用元件,在每個Tab頁引入
- 修改全局配置
// app.wpy export default class extends wepy.app { config = { tabBar: { custom: true, // ... } } }
- 編寫
元件tab-bar
<!-- CustomTabBar.wpy --> <template> <cover-view class="tab-bar"> <cover-view class="tab-bar-border"></cover-view> <cover-view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab"> <cover-image class="icon" src="{{selected == index ? item.selectedIconPath : item.iconPath}}"></cover-image> <cover-view style="color: {{selected == index ? selectedColor : color}}">{{item.text}}</cover-view> </cover-view> </cover-view> </template> <script> import wepy from 'wepy'; export default class CustomTabBar extends wepy.component { props = { selected: { type: String, default: '0' } } data = { color: '#7A7E83', selectedColor: '#6280f5', list: [ { selectedIconPath: '../images/tab_application_pre.png', iconPath: '../images/tab_application.png', pagePath: '/pages/Application', text: '應用' }, { selectedIconPath: '../images/tab_project_pre.png', iconPath: '../images/tab_project.png', pagePath: '/pages/Machines', text: '機械' }, { selectedIconPath: '../images/tab_message_pre.png', iconPath: '../images/tab_message.png', pagePath: '/pages/Message', text: '消息' }, { selectedIconPath: '../images/tab_mine_pre.png', iconPath: '../images/tab_mine.png', pagePath: '/pages/MyHome', text: '我的' } ] } methods = { switchTab(e) { const data = e.currentTarget.dataset; const url = data.path; wx.switchTab({ url }); } } } </script> <style scoped> .tab-bar { position: fixed; bottom: 0; left: 0; right: 0; height: 160rpx; background: white; display: flex; padding-top: 8rpx; padding-bottom: env(safe-area-inset-bottom); .tab-bar-border { background-color: rgba(0, 0, 0, 0.33); position: absolute; left: 0; top: 0; width: 100%; height: 1px; transform: scaleY(0.5); } .tab-bar-item { flex: 1; text-align: center; display: flex; justify-content: center; align-items: center; flex-direction: column; cover-image { width: 27px; height: 27px; margin-bottom: 12rpx; } cover-view { font-size: 10px; } } } </style>
- 在所有 tab 頁引用
<!-- Application.wpy --> <template> <view> <CustomTabBar selected="0" /> </view> </template> <script> import CustomTabBar from '../components/CustomTabBar'; export default class Application extends wepy.page { components = { CustomTabBar } } </script>
二、 官方推薦方式
- 在根目錄建立
檔案夾,建立custom-tab-bar
檔案。index.wpy
實際上,根據官方文檔指引,應該在
目錄下建立custom-tab-bar
、.js
、.wxml
和.wxss
檔案。由于項目小程式使用 wepy 架構,是以建立的是.json
檔案,編譯後會生成相應的檔案。.wpy
<!-- index.wpy --> <template> <cover-view class="tab-bar"> <cover-view class="border"></cover-view> <cover-view wx:for="{{list}}" wx:key="index" class="item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab"> <cover-view wx:if="{{badge[index]}}" class="badge">{{badge[index]}}</cover-view> <cover-image src="{{selected === index ? item.selectedIconPath : item.iconPath}}" /> <cover-view style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</cover-view> </cover-view> </cover-view> </template> <script> // 此處使用的是原生建立元件的方式,保證編譯後符合官方推薦的格式。 Component({ data: { badge: {}, selected: 0, color: '#7A7E83', selectedColor: '#6280f5', list: [ { selectedIconPath: '../images/tab_application_pre.png', iconPath: '../images/tab_application.png', pagePath: '/pages/Application', text: '應用' }, { selectedIconPath: '../images/tab_news_pre.png', iconPath: '../images/tab_news.png', pagePath: '/pages/News', text: '新聞' }, { selectedIconPath: '../images/tab_message_pre.png', iconPath: '../images/tab_message.png', pagePath: '/pages/Message', text: '消息' }, { selectedIconPath: '../images/tab_mine_pre.png', iconPath: '../images/tab_mine.png', pagePath: '/pages/MyHome', text: '我的' } ] }, attached () { }, methods: { switchTab (e) { const data = e.currentTarget.dataset const url = data.path wx.switchTab({ url }) this.setData({ selected: data.index }); }, setTabBarBadge(options) { if (!options) return; const { index, text } = options const badge = this.data.badge || {}; badge[index] = text; this.setData({ badge }); }, removeTabBarBadge(options) { if (!options || options.index === undefined) return; const { index } = options; const badge = this.data.badge || {}; badge[index] = null; this.setData({ badge }); } }, }) // NOTE: 此處導出含 config 屬性的類,是為了保證編譯後生成 .json 檔案 export default class CustomTabBar { config = { component: true } } </script> <style scoped> .tab-bar { position: fixed; bottom: 0; left: 0; right: 0; background: white; display: flex; padding-top: 16rpx; padding-bottom: env(safe-area-inset-bottom); .border { background-color: rgba(0, 0, 0, 0.33); position: absolute; left: 0; top: 0; width: 100%; height: 1px; transform: scaleY(0.5); } .item { position: relative; flex: 1; text-align: center; display: flex; justify-content: center; align-items: center; flex-direction: column; .badge { position: absolute; top: 0; right: 50%; padding: 4rpx 12rpx; border-radius: 28rpx; font-size: 20rpx; background-color: red; color: #fff; z-index: 3; transform: translateX(100%); } cover-image { width: 27px; height: 27px; margin-bottom: 12rpx; } cover-view { font-size: 10px; } } } </style>
- 同方案一的步驟一,修改全局配置。
- 在每個 tab 頁中設定 tabBar 的選中狀态。
<!-- Application.wpy --> export default class Application extends wepy.page { onShow() { if (this.$wxpage && typeof this.$wxpage.getTabBar === 'function') { const tabBar = this.$wxpage.getTabBar(); tabBar.setData({ selected: 0, // 由于Application是第一個tab頁 }); } } }
- 封裝常用操作 tabBar 的方法,包括 tabBar 徽标功能。
// 擷取自定義 tabBar 元件示例 export const getCustomTabBar = ctx => { let tabBar = null; if (ctx && ctx.$wxpage && typeof ctx.$wxpage.getTabBar === 'function') { tabBar = ctx.$wxpage.getTabBar(); } return tabBar; }; // 設定 active tabBar export const setActiveTabBar = (ctx, index = 0) => { const tabBar = getCustomTabBar(ctx); if (tabBar) { tabBar.setData({ selected: index }); } }; // 設定徽标 export const setTabBarBadge = (ctx, options = { index: 0, text: '' }) => { const { index = 0, text = '' } = options; const tabBar = getCustomTabBar(ctx); if (tabBar) { tabBar.setTabBarBadge({ index, text }); } else { wx.setTabBarBadge({ index, text }); } }; // 移除徽标 export const removeTabBarBadge = (ctx, options = { index: 0 }) => { const { index = 0 } = options; const tabBar = getCustomTabBar(ctx); if (tabBar) { tabBar.removeTabBarBadge({ index }); } else { wx.removeTabBarBadge({ index }); } };
注意
在自定義 tabBar 模式下
- 為了保證低版本相容以及區分哪些頁面是 tab 頁,tabBar 的相關配置項仍然需要完整聲明,但這些字段不會作用于自定義 tabBar 的渲染。
- 此時需要開發者提供一個自定義元件來渲染 tabBar,所有 tabBar 的樣式都由該自定義元件渲染。推薦用 fixed 在底部的 cover-view + cover-image 元件渲染樣式,以保證 tabBar 層級相對較高。
- 與 tabBar 樣式相關的接口,如 wx.setTabBarItem 等将失效。
- 每個 tab 頁下的自定義 tabBar 元件執行個體是不同的,可通過自定義元件下的
接口,擷取目前頁面的自定義 tabBar 元件執行個體。
getTabBar
注意
如需實作 tab 選中态,要在目前頁面下,通過
接口擷取元件執行個體,并調用 setData 更新選中态。
getTabBar
參考
- 微信小程式開發文檔
- wepy github issue#2052
- https://www.yuque.com/currywxj/pwgsgm/mci8h7#ZSOWI