react+zarm實(shí)現(xiàn)底部導(dǎo)航欄的示例代碼
需要實(shí)現(xiàn)的效果
需要實(shí)現(xiàn)下面欄目固定,并且點(diǎn)擊時(shí)切換到不同頁(yè)面路由
實(shí)現(xiàn)過(guò)程
1.使用 prop-types 庫(kù)進(jìn)行類型檢查
注意:自 React v15.5 起,React.PropTypes 已移入另一個(gè)包中。請(qǐng)使用 prop-types 庫(kù) 代替。
PropTypes 提供了使用不同驗(yàn)證器的例子:
import PropTypes from 'prop-types'; MyComponent.propTypes = { // 你可以將屬性聲明為 JS 原生類型,默認(rèn)情況下 // 這些屬性都是可選的。 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, // 一個(gè) React 元素。 optionalElement: PropTypes.element, // 一個(gè) React 元素類型(即,MyComponent)。 optionalElementType: PropTypes.elementType, // 你也可以聲明 prop 為類的實(shí)例,這里使用 // JS 的 instanceof 操作符。 optionalMessage: PropTypes.instanceOf(Message), // 你可以讓你的 prop 只能是特定的值,指定它為 // 枚舉類型。 optionalEnum: PropTypes.oneOf(['News', 'Photos']), // 一個(gè)對(duì)象可以是幾種類型中的任意一個(gè)類型 optionalUnion: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.instanceOf(Message) ]), // 可以指定一個(gè)數(shù)組由某一類型的元素組成 optionalArrayOf: PropTypes.arrayOf(PropTypes.number), // 可以指定一個(gè)對(duì)象由某一類型的值組成 optionalObjectOf: PropTypes.objectOf(PropTypes.number), // 可以指定一個(gè)對(duì)象由特定的類型值組成 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` ,確保 // 這個(gè) prop 沒(méi)有被提供時(shí),會(huì)打印警告信息。 requiredFunc: PropTypes.func.isRequired, // 任意類型的必需數(shù)據(jù) requiredAny: PropTypes.any.isRequired, // 你可以指定一個(gè)自定義驗(yàn)證器。它在驗(yàn)證失敗時(shí)應(yīng)返回一個(gè) Error 對(duì)象。 // 請(qǐng)不要使用 `console.warn` 或拋出異常,因?yàn)檫@在 `oneOfType` 中不會(huì)起作用。 customProp: function(props, propName, componentName) { if (!/matchme/.test(props[propName])) { return new Error( 'Invalid prop `' + propName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } }, // 你也可以提供一個(gè)自定義的 `arrayOf` 或 `objectOf` 驗(yàn)證器。 // 它應(yīng)該在驗(yàn)證失敗時(shí)返回一個(gè) Error 對(duì)象。 // 驗(yàn)證器將驗(yàn)證數(shù)組或?qū)ο笾械拿總€(gè)值。驗(yàn)證器的前兩個(gè)參數(shù) // 第一個(gè)是數(shù)組或?qū)ο蟊旧? // 第二個(gè)是他們當(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
,其返回了一個(gè) navigate
(點(diǎn)擊查看用法) 的方法,實(shí)現(xiàn)比較簡(jiǎn)單:
- 從
NavigationContext
拿到navigator
,也就是history
實(shí)例。 - 然后根據(jù)
to、matches
的每項(xiàng)pathnameBase
以及當(dāng)前URL pathname
生成最終的路徑path({pathname, search, hash})
- 根據(jù)是否指定
replace
來(lái)判斷是調(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 實(shí)例 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)計(jì)" 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)簽欄組件
打開(kāi) 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 實(shí)例 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ù)若是變化,便會(huì)執(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)報(bào)錯(cuò)了:Uncaught Error: You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
這是因?yàn)橄胍诤瘮?shù)組件內(nèi)執(zhí)行 useLocation,該組件必須被 Router 高階組件包裹,我們做如下改動(dòng),將 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 實(shí)例 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ù)若是變化,便會(huì)執(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.添加對(duì)應(yīng)的頁(yè)面路由
在 container 文件夾里添加下面三個(gè)模塊的頁(yè)面
// 賬單 import React from 'react' const Home = () => { return <div>賬單</div> } export default Home // 統(tǒng)計(jì) import React from 'react' const Data = () => { return <div>統(tǒng)計(jì)</div> } export default Data // 個(gè)人中心 import React from 'react' const User = () => { return <div>個(gè)人中心</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)計(jì),然后刷新,發(fā)現(xiàn)也是沒(méi)有問(wèn)題。
參考資料
- React-Router v6 新特性解讀及遷移指南
- 系好安全帶,帶你遨游 React Router v6 源碼
- https://zarm.design/#/components/tab-bar
- 使用 PropTypes 進(jìn)行類型檢查
到此這篇關(guān)于react+zarm實(shí)現(xiàn)底部導(dǎo)航欄的示例代碼的文章就介紹到這了,更多相關(guān)react 底部導(dǎo)航欄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解如何在React中監(jiān)聽(tīng)鼠標(biāo)事件
React可以通過(guò)使用React事件系統(tǒng)來(lái)監(jiān)聽(tīng)鼠標(biāo)事件,您可以在React組件中通過(guò)使用特定的事件處理函數(shù)來(lái)注冊(cè)和處理鼠標(biāo)事件,本文小編講給大家詳細(xì)介紹一下如何在React中監(jiān)聽(tīng)鼠標(biāo)事件,需要的朋友可以參考下2023-09-09react-native滑動(dòng)吸頂效果的實(shí)現(xiàn)過(guò)程
這篇文章主要給大家介紹了關(guān)于react-native滑動(dòng)吸頂效果的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用react-native具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06react組件的創(chuàng)建與更新實(shí)現(xiàn)流程詳解
React組件分為函數(shù)組件與class組件;函數(shù)組件是無(wú)狀態(tài)組件,class稱為類組件;函數(shù)組件只有props,沒(méi)有自己的私有數(shù)據(jù)和生命周期函數(shù);class組件有自己私有數(shù)據(jù)(this.state)和生命周期函數(shù)2022-10-10React?Hooks使用startTransition與useTransition教程示例
這篇文章主要為大家介紹了React?Hooks使用startTransition與useTransition教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01create-react-app中添加less支持的實(shí)現(xiàn)
這篇文章主要介紹了react.js create-react-app中添加less支持的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11React父子組件傳值(組件通信)的實(shí)現(xiàn)方法
本文主要介紹了React父子組件傳值(組件通信)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05react之umi配置國(guó)際化語(yǔ)言locale的踩坑記錄
這篇文章主要介紹了react之umi配置國(guó)際化語(yǔ)言locale的踩坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02React?正確使用useCallback?useMemo的方式
這篇文章主要介紹了React?正確使用useCallback?useMemo的方式,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-08-08