【React】路由器 React-Router

发布于:2025-04-20 ⋅ 阅读:(50) ⋅ 点赞:(0)

前端路由指的是一种将浏览器URL与特定页面或视图关联起来的技术。在传统的Web开发中,当用户点击链接或者输入URL时,服务器会接收到请求并返回相应的HTML页面。而在前端路由中,当用户点击链接或者输入URL时,浏览器会根据路由规则对URL进行解析,并使用JavaScript控制页面的展示。

前端路由通常使用JavaScript库来实现,比如React Router、Vue Router等。它们允许开发者定义路由规则,并根据这些规则来显示不同的组件或页面

前端路由可以提高Web应用的性能和用户体验,因为它允许应用实现快速的页面切换和动态的内容加载,同时减少了服务器的负载

安装

官网:https://reactrouter.com/home

ReactRouter包含三个内容:(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/#/home


History(在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){  //函数B
                    return function(){  //函数C
                        fn()
                    }
                }

                let myFn=HOF(
                    ()=>{  //函数A
                        console.log("哈哈哈哈")
                    }
                )

                myFn();
            </script>

高阶组件HOC,向一个函数A传递一个组件C作为参数,最后返回一个新的组件(使用高阶组件的目的,为了组件的二次加工,或者功能逻辑判断)

项目启动后,路由中的Power函数会被执行


网站公告

今日签到

点亮在社区的每一天
去签到