- 安裝
- 路由模式
- 路由組件和屬性 (Link、NavLink、Outlet、Routes、Navigate、element)
- 路由傳參 ( Hook:useParams 、useSearchParams )
- 路由跳轉(Hook:useNavigate)
- 路由的構建
前端路由指的是一種將瀏覽器URL與特定頁面或視圖關聯起來的技術。在傳統的Web開發中,當用戶點擊鏈接或者輸入URL時,服務器會接收到請求并返回相應的HTML頁面。而在前端路由中,當用戶點擊鏈接或者輸入URL時,瀏覽器會根據路由規則對URL進行解析,并使用JavaScript控制頁面的展示。
前端路由通常使用JavaScript庫來實現,比如React Router、Vue Router等。它們允許開發者定義路由規則,并根據這些規則來顯示不同的組件或頁面
前端路由可以提高Web應用的性能和用戶體驗,因為它允許應用實現快速的頁面切換和動態的內容加載,同時減少了服務器的負載
安裝
官網:https://reactrouter.com/homeReactRouter包含三個內容:(1) react-router:核心庫;(2) react-router-dom:正常PC用的;(3) react-router-native:移動native用的當前使用版本:"react-router-dom": "^6.30.0"安裝:npm install react-router-dom@6
路由模式
React的路由需要在某個模式下包裹使用,不能單獨使用
HashRouter(哈希路由):類似a標簽錨點,在本頁跳轉,所以拿不到歷史記錄,因為沒有跳出當前頁面http://localhost:3000/#/homeHistory(在React中叫BrowserRouter,歷史記錄模式):模擬歷史記錄模式,可以有前進后退的歷史記錄http://localhost:3000/home//刷新頁面,<BrowserRouter>會將當前路由發送到服務器//需要后端配合就是當收到請求的url不是功能性的,而是前端路由時,重新加載入口html文件
路由組件和屬性 (Link、NavLink、Outlet、Routes、Navigate、element)
Link:負責跳轉NavLink:將包裹的內容渲染為a標簽,并給Link加上一個樣式active類,設置類的樣式達到激活菜單的效果Outlet:相當于一個占位符,目的就是為了用來占位展示當前組件對應的Home1和Home2(類似于vue中的router-view)Routes:路由攔截并展示對應的組件<Routes><Route path={"/home"} element={<Home/>}/><Route path={"/about"} element={<About/>}/></Routes>element:表示對應組件Navigate:相對于重定向路由嵌套的時候:子組件的path不需要寫斜杠"/",直接寫就好<Route path={"/home"} element={<Home/>}><Route path="home1" element={<Home1/>}/><Route path="home2" element={<Home2/>}/></Route>默認展示組件:<Route index element={<Home1/>}/> <!--index表示默認要展示的組件,去掉path-->
src\App.js
import './App.scss';
import {HashRouter, //-----路由容器,裝路由組件// Link, //-----跳轉Routes, //-----路由攔截展示的容器Route, //-----攔截路徑,設置展示組件Navigate, //-----類似重定向NavLink, //-----跳轉,帶active類,但需要自己寫樣式// BrowserRouter //-----路由容器,裝路由組件//Outlet //-----占位符,用來展示嵌套路由的子組件的內容
} from 'react-router-dom';import Home from "./Home";
import About from "./About";
import Home1 from "./Hom1";
import Home2 from "./Home2";// 用戶亂輸入地址欄url,則返回404頁面組件
const Err=()=><div>Error錯誤404頁面</div>//React-Router案例
function App() {return (<>{/*<BrowserRouter>*/}<HashRouter future={{v7_startTransition: true,v7_relativeSplatPath: true/*解決:使用react-router-dom@6.30.0版本時,組件默認打印未來版本的警告信息,影響項目代碼功能調試*/}}>{/*<Link to={"/home"}>Home</Link>*/} {/*你要去哪里*/}<NavLink to={"/home"}>Home</NavLink>{/*<Link to={"/about"}>About</Link>*/}{/*<NavLink to={"/about/月亮/25"}>About</NavLink>*/} {/*路由傳參*/}<NavLink to={"/about?a=1&b=2"}>About</NavLink><Routes> {/*攔截并展示對應的組件*/}<Route path="/" element={<Navigate to={"/home"}/>}/> {/*通用攔截*/}<Route path={"/home"} element={<Home/>}>{/*<Route path={"home1"} element={<Home1/>}/> /!*嵌套子路由*!/*/}<Route index element={<Home1/>}/> {/*index表示默認要展示的組件,去掉path*/}<Route path={"home1"} element={<Home1/>}/> {/*加上這一行即可,因為上一行沒法攔截對應路由,它本身還是要寫*/}<Route path={"home2"} element={<Home2/>}/></Route>{/*<Route path={"/home/"} element={<Navigate to={"/home/home1"}/>}/> /!*默認要展示的組件(自想方法)*!/*/}{/*<Route path={"/about/:name/:id"} element={<About/>}/>*/} {/*路由接參*/}<Route path={"/about"} element={<About/>}/><Route path={"*"} element={<Err/>}/> {/*錯誤404頁面*/}</Routes></HashRouter>{/*</BrowserRouter>*/}</>);
}export default App;
import {NavLink, Outlet} from "react-router-dom";const Home = () => <div><h1>Home</h1><NavLink to={"/home/home1"}>Home1</NavLink><NavLink to={"/home/home2"}>Home2</NavLink><Outlet/> {/*占位符,用來展示Home1和Home2內容的*/}
</div>;export default Home;
路由傳參 ( Hook:useParams 、useSearchParams )
import引入的路由都是引入的屬性(大寫開頭);除了屬性之外,路由還可以引入方法(所有的方法都是useXxx的格式)
路由傳參(useParams):1. <NavLink to={"/about/25"}>About</NavLink> <!--帶參跳轉,可以傳遞多個參數,右斜杠隔開-->2. <Route path={"/about/:id"} element={<About/>}/> <!--這里會有參數并且是通過id接收-->3.組件獲取import {useParams <!--獲取路由傳參的方法-->} from 'react-router-dom';const params=useParams();console.log(params.id); <!--{}-->路由傳參第二種方式(useSearchParams):1. <NavLink to={"/about?a=1&b=2"}>About</NavLink> <!--傳了兩個參數 a,b-->2. <Route path={"/about"} element={<About/>}/>3.獲取參數import {useSearchParams} from 'react-router-dom';const [search]=useSearchParams();console.log(search.get("a")); <!--通過get方法獲取指定參數-->
import {// useParams, //獲取路由傳參的方法useSearchParams
} from 'react-router-dom';const About=()=> {// const params=useParams();// console.log(params.name);const [search,setSearch]=useSearchParams();console.log(search.get("a"));console.log(search); //{size:2} 遍歷出來search.forEach((v,i)=>{console.log(i,v)})return (<h2>About</h2>)
}export default About;
路由跳轉(Hook:useNavigate)
React跳轉(useNavigate):(在Vue中,push() 會產生歷史記錄,replace() 不會產生歷史記錄)import {useNavigate} from "react-router-dom";const navigate=useNavigate();navigate("/home/home2"); <!--這種頁面跳轉相當于添加了一條歷史記錄-->navigate("/home/home2",{replace: true}); <!--這種頁面跳轉相當于替換掉了一條歷史記錄-->navigate(-1) <!--返回 -1:上一頁,0:當前頁,1:下一頁-->
import {useNavigate} from "react-router-dom";const Home1=()=>{const navigate=useNavigate();const goHome2=()=> {// navigate("/home/home2"); //這種頁面跳轉相當于添加了一條歷史記錄navigate("/home/home2",{replace: true}); //這種頁面跳轉相當于替換掉了一條歷史記錄}return (<div><h2>Home1</h2><button onClick={goHome2}>跳到Home2</button></div>)
}export default Home1;
import {useNavigate} from "react-router-dom";const Home2=()=>{const navigate=useNavigate();const goBack=()=>{navigate(-1)}return (<div><h2>Home2</h2><button onClick={goBack}>返回</button></div>)
}export default Home2;
路由的構建
src\index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';import {HashRouter} from "react-router-dom";const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<HashRouter><App /></HashRouter>
);
src\App.js
import './App.css';
import Routers from './router'function App() {return (<div className="App"><Routers/></div>);
}export default App;
router\index.js
import {useRoutes,Navigate,
} from 'react-router-dom'
import Power from "./power"; //進行權限判斷處理import Home from '../pages/home'
import Login from '../pages/login'
import Admin from '../pages/home/admin'
import Notice from "../pages/home/notice"
import Student from "../pages/home/student"//路由配置的組件
const Routers=()=>{return useRoutes([{path:'/',element:<Navigate to={"/login"}/>},{path:'/login',element:<Login/>},{path:'/home',// element:<Home/>,// element:Power(<Home/>,"/home"), /*高階函數*/element:<Power path='/home' ele={<Home/>}/>, /*高階組件*/children:[ /*子路由*/{index:"index", /*默認展示當前的子組件*/// path:'admin', /*子路由不需要 /admin 這樣寫,斜杠不需要*/element:<Power path='/home/notice' ele={<Notice/>}/>},{path:'notice',element:<Power path='/home/notice' ele={<Notice/>}/>},{path:'student',element:<Power path='/home/student' ele={<Student/>}/>},{path:'admin',element:<Power path='/home/admin' ele={<Admin/>}/>}]}])}export default Routers;
router\power.js 高階組件
const Power=(props)=>{console.log("Power執行") //避免多次重復執行,在router中應寫作組件<power/>,而不是直接調用Power()console.log(props)//這里攔截判斷是否可以返回當前組件//取出sessionStorage中的power比對,如果本地數據中有就返回當前組件,如果本地用戶數據中沒有就不返回當前組件let power=JSON.parse(sessionStorage.getItem("power")); //[{},{},{}]for(let i=0;i<power.length;i++){if(power[i].link.indexOf(props.path)!==-1){ //有權限訪問return <>{props.ele}</>}}return <div><h1>沒有權限</h1></div>; //循環完了都沒找到有的話,就是沒有權限}export default Power;
權限攔截:
現在的路由是攔截到請求,直接返回對應的組件,實際上應該先查看用戶是否有權限訪問需要寫一個函數,接收一個組件為參數。如果有權限,就返回組件;如果沒有權限就返回登錄或者錯誤組件{path:'/home',// element:<Home/>, -------以前直接返回組件element:Power(<Home/>), -------把組件轉入Power函數,在函數內部進行邏輯判斷,最后根據權限返回需要展示的組件}element:Power(<Home/>) -------向一個函數傳遞一個組件作為參數,我們稱為高階組件,函數負責邏輯代碼,組件負責頁面展示高階組件,源于高階函數,高階函數就是把函數A作為參數傳給函數B,調用函數B返回一個新的函數C<script>function HOF(fn){ //函數Breturn function(){ //函數Cfn()}}let myFn=HOF(()=>{ //函數Aconsole.log("哈哈哈哈")})myFn();</script>高階組件HOC,向一個函數A傳遞一個組件C作為參數,最后返回一個新的組件(使用高階組件的目的,為了組件的二次加工,或者功能邏輯判斷)項目啟動后,路由中的Power函數會被執行