react+zarm實現(xiàn)底部導(dǎo)航欄的示例代碼
需要實現(xiàn)的效果
需要實現(xiàn)下面欄目固定,并且點擊時切換到不同頁面路由

實現(xiàn)過程
1.使用 prop-types 庫進行類型檢查
注意:自 React v15.5 起,React.PropTypes 已移入另一個包中。請使用 prop-types 庫 代替。
PropTypes 提供了使用不同驗證器的例子:
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以將屬性聲明為 JS 原生類型,默認情況下
// 這些屬性都是可選的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括數(shù)字、字符串、元素或數(shù)組)
// (或 Fragment) 也包含這些類型。
optionalNode: PropTypes.node,
// 一個 React 元素。
optionalElement: PropTypes.element,
// 一個 React 元素類型(即,MyComponent)。
optionalElementType: PropTypes.elementType,
// 你也可以聲明 prop 為類的實例,這里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),
// 你可以讓你的 prop 只能是特定的值,指定它為
// 枚舉類型。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// 一個對象可以是幾種類型中的任意一個類型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 可以指定一個數(shù)組由某一類型的元素組成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// 可以指定一個對象由某一類型的值組成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// 可以指定一個對象由特定的類型值組成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// 你可以在任何 PropTypes 屬性后面加上 `isRequired` ,確保
// 這個 prop 沒有被提供時,會打印警告信息。
requiredFunc: PropTypes.func.isRequired,
// 任意類型的必需數(shù)據(jù)
requiredAny: PropTypes.any.isRequired,
// 你可以指定一個自定義驗證器。它在驗證失敗時應(yīng)返回一個 Error 對象。
// 請不要使用 `console.warn` 或拋出異常,因為這在 `oneOfType` 中不會起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一個自定義的 `arrayOf` 或 `objectOf` 驗證器。
// 它應(yīng)該在驗證失敗時返回一個 Error 對象。
// 驗證器將驗證數(shù)組或?qū)ο笾械拿總€值。驗證器的前兩個參數(shù)
// 第一個是數(shù)組或?qū)ο蟊旧?
// 第二個是他們當(dāng)前的鍵。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
安裝依賴:
npm i prop-types -S

2.使用 useNavigate
v6 用 useNavigate 替代了 useHistory,其返回了一個 navigate (點擊查看用法) 的方法,實現(xiàn)比較簡單:
- 從
NavigationContext拿到navigator,也就是history實例。 - 然后根據(jù)
to、matches的每項pathnameBase以及當(dāng)前URL pathname生成最終的路徑path({pathname, search, hash}) - 根據(jù)是否指定
replace來判斷是調(diào)用replace還是push方法
// v5
import { useHistory } from 'react-router-dom';
function MyButton() {
let history = useHistory();
function handleClick() {
history.push('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
現(xiàn)在,history.push() 將替換為 navigation():
// v6
import { useNavigate } from 'react-router-dom';
function MyButton() {
let navigate = useNavigate();
function handleClick() {
navigate('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
3.編寫標(biāo)簽欄組件
新建 components/NavBar/index.jsx 文件,用于編寫底部導(dǎo)航欄,代碼如下所示:
import React, { useState } from 'react';
import PropTypes from 'prop-types'
import { TabBar } from 'zarm';
import { useNavigate, useLocation } from 'react-router-dom';
import CustomIcon from '../CustomIcon'
import s from './style.module.less';
const NavBar = ({ showNav }) => {
const location = useLocation() // 拿到 location 實例
const { pathname } = location // 獲取當(dāng)前路徑
console.log('navbar pathname', pathname)
const [activeKey, setActiveKey] = useState(pathname);
const navigate = useNavigate()
const changeTab = (path) => {
setActiveKey(path)
navigate(path)
}
return (
<TabBar visible={showNav} className={s.tab} activeKey={activeKey} onChange={changeTab}>
<TabBar.Item
itemKey="/"
title="賬單"
icon={<CustomIcon type="zhangdan" />}
/>
<TabBar.Item
itemKey="/data"
title="統(tǒng)計"
icon={<CustomIcon type="tongji" />}
/>
<TabBar.Item
itemKey="/user"
title="我的"
icon={<CustomIcon type="user" />}
/>
</TabBar>
);
};
NavBar.propTypes = {
showNav: PropTypes.bool
}
export default NavBar;
新建 components/NavBar/style.module.less 文件,用于編寫底部導(dǎo)航欄樣式,代碼如下所示:
.tab {
border-top: 1px solid #e9e9e9;
}
4.使用標(biāo)簽欄組件
打開 App.jsx,添加如下代碼:
import React, { useState, useEffect } from 'react'
import NavBar from '@/components/NavBar';
import { Routes, Route, useLocation, BrowserRouter } from 'react-router-dom'
import { ConfigProvider } from 'zarm';
import routes from '../src/router'
function App() {
const location = useLocation() // 拿到 location 實例
const { pathname } = location // 獲取當(dāng)前路徑
const needNav = ['/', '/data', '/user'] // 需要底部導(dǎo)航欄的路徑
const [showNav, setShowNav] = useState(false) // 是否展示 Nav
useEffect(() => {
setShowNav(needNav.includes(pathname))
}, [pathname]) // [] 內(nèi)的參數(shù)若是變化,便會執(zhí)行上述回調(diào)函數(shù)
return <BrowserRouter>
<ConfigProvider primaryColor={'#007fff'}>
<Routes>
{
routes.map(route => <Route key={route.path} path={route.path} element={<route.component />}></Route>)
}
</Routes>
</ConfigProvider>
<NavBar showNav={showNav} />
</BrowserRouter>
}
export default App
我們發(fā)現(xiàn)報錯了:Uncaught Error: You cannot render a <Router> inside another <Router>. You should never have more than one in your app.

這是因為想要在函數(shù)組件內(nèi)執(zhí)行 useLocation,該組件必須被 Router 高階組件包裹,我們做如下改動,將 App.jsx 的 BrowserRouter 組件,前移到 main.jsx 內(nèi),如下:
App.jsx 里面
import React, { useState, useEffect } from 'react'
import NavBar from '@/components/NavBar';
import { Routes, Route, useLocation } from 'react-router-dom'
import { ConfigProvider } from 'zarm';
import routes from '../src/router'
function App() {
const location = useLocation() // 拿到 location 實例
const { pathname } = location // 獲取當(dāng)前路徑
const needNav = ['/', '/data', '/user'] // 需要底部導(dǎo)航欄的路徑
const [showNav, setShowNav] = useState(false) // 是否展示 Nav
useEffect(() => {
setShowNav(needNav.includes(pathname))
}, [pathname]) // [] 內(nèi)的參數(shù)若是變化,便會執(zhí)行上述回調(diào)函數(shù)
return <>
<ConfigProvider primaryColor={'#007fff'}>
<Routes>
{
routes.map(route => <Route key={route.path} path={route.path} element={<route.component />}></Route>)
}
</Routes>
</ConfigProvider>
<NavBar showNav={showNav} />
</>
}
export default App
main.jsx :
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import 'lib-flexible/flexible'
import './index.css'
import App from './App'
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
)
5.添加對應(yīng)的頁面路由
在 container 文件夾里添加下面三個模塊的頁面

// 賬單
import React from 'react'
const Home = () => {
return <div>賬單</div>
}
export default Home
// 統(tǒng)計
import React from 'react'
const Data = () => {
return <div>統(tǒng)計</div>
}
export default Data
// 個人中心
import React from 'react'
const User = () => {
return <div>個人中心</div>
}
export default User
然后在 router/index.js 添加路由:
import Login from '@/container/Login'
import Home from '@/container/Home'
import Data from '@/container/Data'
import User from '@/container/User'
const routes = [
{
path: "/login",
component: Login
},{
path: "/",
component: Home
},{
path: "/data",
component: Data
},{
path: "/user",
component: User
}
];
export default routes
6.效果

我們可以切換到統(tǒng)計,然后刷新,發(fā)現(xiàn)也是沒有問題。

參考資料
- React-Router v6 新特性解讀及遷移指南
- 系好安全帶,帶你遨游 React Router v6 源碼
- https://zarm.design/#/components/tab-bar
- 使用 PropTypes 進行類型檢查
到此這篇關(guān)于react+zarm實現(xiàn)底部導(dǎo)航欄的示例代碼的文章就介紹到這了,更多相關(guān)react 底部導(dǎo)航欄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react組件的創(chuàng)建與更新實現(xiàn)流程詳解
React組件分為函數(shù)組件與class組件;函數(shù)組件是無狀態(tài)組件,class稱為類組件;函數(shù)組件只有props,沒有自己的私有數(shù)據(jù)和生命周期函數(shù);class組件有自己私有數(shù)據(jù)(this.state)和生命周期函數(shù)2022-10-10
React?Hooks使用startTransition與useTransition教程示例
這篇文章主要為大家介紹了React?Hooks使用startTransition與useTransition教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
create-react-app中添加less支持的實現(xiàn)
這篇文章主要介紹了react.js create-react-app中添加less支持的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
React?正確使用useCallback?useMemo的方式
這篇文章主要介紹了React?正確使用useCallback?useMemo的方式,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-08-08

