- 安装
- 路由模式
- 路由组件和属性 (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函数会被执行