We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最近在做 Taro 项目,有微信小程序和 H5 两端,因导航栏样式无法满足要求,需实现自定义 TabBar。
目前 Taro for H5 未默认支持自定义 TabBar,详见 #10049。
相关链接:
注意事项:
custom-tab-bar
src
tabBar
custom: true
实现思路:
对于微信小程序来说,Taro 已经支持了,这个不多说,按要求写就能正常显示。而 H5 则在 TabBar 页面中引入 custom-tab-bar 即可。有两个问题,一是内置的 TabBar 仍然存在,通过样式将其屏蔽掉。二是,在 TabBar 页面切换时,由于组件不会重新挂载,可能不会触发重新渲染,为避免 Tab 的高亮状态不正确,需在 onShow 时机进行设置。
onShow
引入 custom-tab-bar 页面的方式有两种,一是在每个 TabBar 页面中手动引入(一般不会很多),二是通过插件(比如 taro-inject-component-loader)自动插入到每个页面。后者,还需要在组件内进一步判断,若是 TabBar 的路由则显示自定义 TabBar 的内容,否则不显示。
下文以 React 为例,并选择第二种方式导入自定义 TabBar。
小程序配置 app.config.js,记得完整配置 tabBar。
app.config.js
export default defineAppConfig({ tabBar: { + custom: true, // ... }, })
安装 taro-inject-component-loader,如果手动引入 custom-tab-bar 可以忽略。
taro-inject-component-loader
$ pnpm add taro-inject-component-loader -D
编译配置 config/index.js 如下:
config/index.js
import path from 'path' export default { // ... alias: { + '@': path.resolve('./src'), }, h5: { // ... webpackChain(chain) { chain.merge({ module: { rule: { injectBaseComponentLoader: { test: /\.jsx$/, use: [ { + loader: 'taro-inject-component-loader', + options: { + importPath: '@/custom-tab-bar', + }, }, ], }, }, }, }) }, }, }
可关注下 taro-inject-component-loader 里 isPage 的默认配置是否满足要求,特别是有分包时,它只会插入到页面组件里,详见。
isPage
编写 custom-tab-bar 组件,几个注意点:
injectBaseComponentLoader.use[].options.isPage
Taro.eventCenter
import
Taro.getTabBar()
src/constants/index.js 👇
src/constants/index.js
export const IS_H5 = process.env.TARO_ENV === 'h5' export const ROUTE = { INDEX: '/pages/index/index', MINE: '/pages/mine/index', } export const TAB_BAR_ROUTES = [ROUTE.INDEX, ROUTE.MINE] export const EVENT_NAME = { TAB_BAR_PAGE_VISIBLE: 'tab_bar_page_visible', }
src/custom-tab-bar/index.jsx 👇
src/custom-tab-bar/index.jsx
import { useMemo, useState } from 'react' import { View, Image } from '@tarojs/components' import Taro, { eventCenter } from '@tarojs/taro' import { IS_H5, EVENT_NAME, TAB_BAR_ROUTES } from '@/constants' import indexIcon from '@/images/icon-index.png' import indexIconActive from '@/images/icon-index-active.png' import mineIcon from '@/images/icon-mine.png' import mineIconActive from '@/images/icon-mine-active.png' // 样式文件碍于篇幅原因,就不贴出来了,请看文末完整示例 import './index.scss' const tabBarConfig = { color: '#7A7E83', selectedColor: '#3CC51F', backgroundColor: '#F7F7F7', borderStyle: 'black', list: [ { iconPath: IS_H5 ? indexIcon : '../images/icon-index.png', selectedIconPath: IS_H5 ? indexIconActive : '../images/icon-index-active.png', pagePath: '/pages/index/index', text: '首页', }, { iconPath: IS_H5 ? mineIcon : '../images/icon-mine.png', selectedIconPath: IS_H5 ? mineIconActive : '../images/icon-mine-active.png', pagePath: '/pages/mine/index', text: '我的', }, ], } export default function CustomTabBar() { const [selected, setSelected] = useState(-1) const onChange = (index, url) => { setSelected(index) Taro.switchTab({ url }) } const currentRoute = useMemo(() => { const pages = Taro.getCurrentPages() const currentPage = pages[pages.length - 1] const route = currentPage.route?.split('?')[0] return IS_H5 ? route : `/${route}` }, []) const isTabBarPage = useMemo(() => { return tabBarConfig.list.some(item => { // 如有做路由映射,此处可能要调整判断条件 const matched = TAB_BAR_ROUTES.find(route => route === currentRoute) return matched && item.pagePath === matched }) }, [currentRoute]) // 以避免多余的监听,特别是 rerender 时 useState(() => { if (!isTabBarPage) return eventCenter.on(EVENT_NAME.TAB_BAR_PAGE_VISIBLE, index => setSelected(index)) }) const element = useMemo(() => { if (IS_H5 && !isTabBarPage) return null return ( <View className="tab-bar"> {tabBarConfig.list.map((item, index) => ( <View key={item.pagePath} className="tab-bar-item" onClick={() => onChange(index, item.pagePath)} > <Image className="tab-bar-icon" src={selected === index ? item.selectedIconPath : item.iconPath} /> <View className="tab-bar-text" style={{color: selected === index ? tabBarConfig.selectedColor : tabBarConfig.color}} > {item.text} </View> </View> ))} </View> ) }, [selected, isTabBarPage]) return element }
抽成 Hook src/hooks/use-tab-bar.js 👇
src/hooks/use-tab-bar.js
import Taro, { useDidShow } from '@tarojs/taro' import { EVENT_NAME } from '@/constants' export default function useTabBar(selectedIndex) { useDidShow(() => { Taro.eventCenter.trigger(EVENT_NAME.TAB_BAR_PAGE_VISIBLE, selectedIndex) }) }
页面使用 src/pages/index/index.jsx 👇
src/pages/index/index.jsx
import { View, Text } from '@tarojs/components' import useTabBar from '@/hooks/use-tab-bar' import './index.scss' export default function Index() { useTabBar(0) return ( <View className="index"> <Text>首页</Text> </View> ) }
H5 端内置的 TabBar 组件还是会渲染的,要通过样式来隐藏。src/app.scss 👇
src/app.scss
.taro-tabbar__tabbar { display: none !important; }
完整示例 👉 taro-custom-tab-bar。
有个体验上的问题,自定义 TabBar 在各个 TabBar 页面初始化时都会创建一个新的组件实例导致,导致切换 Tab 时图片闪烁,可以关注 #7302。
The end.
The text was updated successfully, but these errors were encountered:
RN 可以兼容么
Sorry, something went wrong.
嗯...没写过 RN,你可以试试~
显示tabbar没有问题但是h5端useLoad每一次切换都执行跟小程序端一样第一次显示执行,这个问题怎么解决
试了下,没有这种问题,参考 taro-custom-tab-bar。
No branches or pull requests
背景
最近在做 Taro 项目,有微信小程序和 H5 两端,因导航栏样式无法满足要求,需实现自定义 TabBar。
目前 Taro for H5 未默认支持自定义 TabBar,详见 #10049。
开始之前
相关链接:
注意事项:
custom-tab-bar
,且放在src
目录下。tabBar
字段,一是为了向下兼容,二是不配置的情况下 H5 端切换页面的体验很差。后者不确定是否因为 Taro 不支持所以没做兼容。custom: true
编译为 H5 时是无效的。实现思路:
对于微信小程序来说,Taro 已经支持了,这个不多说,按要求写就能正常显示。而 H5 则在 TabBar 页面中引入
custom-tab-bar
即可。有两个问题,一是内置的 TabBar 仍然存在,通过样式将其屏蔽掉。二是,在 TabBar 页面切换时,由于组件不会重新挂载,可能不会触发重新渲染,为避免 Tab 的高亮状态不正确,需在onShow
时机进行设置。引入
custom-tab-bar
页面的方式有两种,一是在每个 TabBar 页面中手动引入(一般不会很多),二是通过插件(比如 taro-inject-component-loader)自动插入到每个页面。后者,还需要在组件内进一步判断,若是 TabBar 的路由则显示自定义 TabBar 的内容,否则不显示。实现
小程序配置
app.config.js
,记得完整配置tabBar
。export default defineAppConfig({ tabBar: { + custom: true, // ... }, })
安装
taro-inject-component-loader
,如果手动引入custom-tab-bar
可以忽略。编译配置
config/index.js
如下:编写
custom-tab-bar
组件,几个注意点:custom-tab-bar
组件内容。这个可以在injectBaseComponentLoader.use[].options.isPage
通过自定义正则限制只在 TabBar 页注入组件。custom-tab-bar
隐藏 → 显示 → 隐藏的过程,影响用户体验,要使用一定的缓存处理。onShow
生命周期设置 Tab 的高亮状态,以确保 Tab 正确显示。onShow
生命周期(详见),因此这里使用Taro.eventCenter
来监听页面组件的onShow
生命周期。import
导入的方式,Taro 会自动根据 TabBar 配置处理(详见)。而 H5 由于官方未支持,则需要手动import
导入。Taro.getTabBar()
获取组件实例,进而更新组件状态。但在 H5 端并未提供Taro.getTabBar()
方法,因此它无法兼容小程序和 H5 两端。下面我用 Functional Component 并统一用 Taro 的消息机制来更新组件的状态。src/constants/index.js
👇src/custom-tab-bar/index.jsx
👇展开
抽成 Hook
src/hooks/use-tab-bar.js
👇页面使用
src/pages/index/index.jsx
👇H5 端内置的 TabBar 组件还是会渲染的,要通过样式来隐藏。
src/app.scss
👇最后
完整示例 👉 taro-custom-tab-bar。
有个体验上的问题,自定义 TabBar 在各个 TabBar 页面初始化时都会创建一个新的组件实例导致,导致切换 Tab 时图片闪烁,可以关注 #7302。
The end.
The text was updated successfully, but these errors were encountered: