本文最后更新于 2024-03-22T23:32:52+00:00
                  
                  
                
              
            
            
              
                
                路由的演变 之前,部署到服务器的前端项目是由多个 HTML 文件组成,每个 HTML 都有对应服务器路径,前端称其为路由,路由之间使用location.href跳转,跳转路径就是另一个 HTML 的服务器地址。这时候的路由是由后端来管理的 后面单页应用流行,部署到服务器的前端项目就只有一个 HTML 文件,对应一个服务器路径。这时候为满足不同页面的展示,就需要借助框架提供的路由能力,至此路由的管理转移到前端身上。
路由的组成 即location的组成:location.protocal协议location.host 域名location.port 端口(多数省略了)location.pathname  路径location.search  参数,[? 后面,# 之前)的内容location.hash  锚点,# 后面的内容
路由的分类 单页应用下,分为:hash、historyhash:  路由上带 #,内容为 # 后面,用它来区分页面; 不需要服务端配合。
history:  路由上不带 #,内容为[域名后面,? 之前),用它来区分页面; 需要服务端配合。因为部署到服务器后,该模式实际上访问服务器的资源,但单页应用只有一个指向 html 的路径,所以这样访问会返回 404,一般需要配置让其指向 html 的路径
路由实现的核心原理 核心原理:监听路径的变化,找到该路径对应的组件,然后渲染到相应位置,并注入 router 等上下文。其中的对应关系就是我们常写的路由配置项。 
react-router 官网:React Router 
基本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import  "./App.css" ;import  { BrowserRouter , Routes , Route , Outlet  } from  "react-router-dom" ;const  Menu  = ( ) => (   <div >     <header >        <ul  style ={{  display:  "flex " }}>          <a  href ="/" > 首页</a >          <span  style ={{  margin:  "0  10px " }}> |</span >          <a  href ="/list" > 新闻列表</a >          <span  style ={{  margin:  "0  10px " }}> |</span >          <a  href ="/about" > 关于我们</a >        </ul >      </header >      <Outlet  />    </div >   );function  App ( ) {   return  (     <BrowserRouter >       <Menu  />        <Routes >          <Route  path ="/"  element ={ <div > 首页 page</div > }></Route >          <Route  path ="/list"  element ={ <div > 新闻列表 page</div > }></Route >          <Route  path ="/about"  element ={ <div > 关于我们 page</div > }></Route >        </Routes >      </BrowserRouter >     ); }export  default  App ;
 
基本原理(手撸简版) 简单手撸react-router-dom核心原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 import  React  from  "react" ;const  LocationContext  = React .createContext ({});const  NavigationContext  = React .createContext ({});export  function  BrowserRouter ({ children } ) {   return  (          <LocationContext.Provider  value ={{  location:  window.location  }}>       <NavigationContext.Provider  value ={{  navigator:  window.history  }}>          {children}       </NavigationContext.Provider >      </LocationContext.Provider >     ); }export  function  useLocation ( ) {   return  React .useContext (LocationContext ).location ; }export  function  useNavigation ( ) {   return  React .useContext (NavigationContext ).navigator ; }export  function  findRoute (routes, pathname ) {   routes.find (({ path } ) =>  path === pathname);   return ; }export  function  useRoutes (routes ) {      const  location = useLocation ();      const  pathname = location.pathname  || "/" ;      const  parentRoute = findRoute (routes, pathname);      return  parentRoute?.element ; }export  function  childrenToRoutes (children ) {   const  routes = [];      React .Children .forEach (children, (node ) =>  {          const  { path, element } = node.props ;          const  route = { path, element };          if  (node.props .children ) {       route.children  = childrenToRoutes (node.props .children );     }          routes.push (route);   });      return  routes; }export  function  Routes ({ children } ) {   return  useRoutes (childrenToRoutes (children)); }
 
手撸 Router 核心原理:监听路径的变化,找到该路径对应的组件,然后渲染到相应位置,并注入 router 等上下文。其中的对应关系就是我们常写的路由配置项。 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 <!DOCTYPE html > <html  lang ="zh" >    <head >      <meta  charset ="UTF-8"  />      <meta  name ="viewport"  content ="width=device-width, initial-scale=1.0"  />      <title > base-index-html</title >    </head >    <body >      <div >        <nav >          <a  href ="#" > 首页</a >          <a  href ="#about" > 关于我们</a >          <a  href ="#list" > 新闻列表</a >          <a  href ="#post" > 新闻详情</a >        </nav >        <section >          <div  class ="router-view" > </div >        </section >      </div >      <script >       class  Router  {         constructor (routes ) {           this .routes  = routes;           this .init ();         }         init ( ) {           window .addEventListener ("hashchange" , () =>  this .onHashChange ());           window .addEventListener ("load" , () =>  this .onHashChange ());         }         onHashChange ( ) {           const  hash = window .location .hash .slice (1 );           const  route = this .findRoute (hash);           this .updateView (route);         }         findRoute (hash ) {           return  this .routes .find ((route ) =>  route.path  === "/"  + hash);         }         updateView (route ) {           const  viewEle = document .querySelector (".router-view" );           viewEle.innerHTML  = route ? route.element  : "404" ;         }         push (path ) {           window .location .hash  = path.slice (1 );         }       }       const  routes = [         {           path : "/" ,           element : `              <div>               <div>首页 page</div>               <button onclick="router.push('/about')">去 about</button>             </div>           ` ,        },         {           path : "/list" ,           element : `              <div>               <div>新闻列表 page</div>             </div>           ` ,        },         {           path : "/about" ,           element : `              <div>               <div>关于我们 page</div>             </div>           ` ,        },         {           path : "/post" ,           element : `              <div>               <div>新闻详情 page</div>             </div>           ` ,        },       ];       const  router = new  Router (routes);      </script >    </body > </html >