核心API

  • Router
  • navigate
  • Link

    Router

    看看使用起来的 api:

    1. const App = () => (
    2. <Router
    3. routes={[
    4. { path: '/home', component: <Home /> },
    5. { path: '/articles', component: <Articles /> }
    6. ]}
    7. />
    8. )
  • 接收了 routes 参数,是一个数组,数组中每个对象中有url路径和对应要渲染的组件

  • 监听 url 变化,渲染新组建

    实现

    1. export default function Router ({ routes }) {
    2. // 存储当前 url path,方便其变化时引发自身重渲染,以返回新的 url 对应的组件
    3. const [currentPath, setCurrentPath] = useState(window.location.pathname);
    4. useEffect(() => {
    5. const onLocationChange = () => {
    6. // 将 url path 更新到当前数据流中,触发自身重渲染
    7. setCurrentPath(window.location.pathname);
    8. }
    9. // 监听 popstate 事件,该事件由用户点击浏览器前进/后退时触发
    10. window.addEventListener('popstate', onLocationChange);
    11. return () => window.removeEventListener('popstate', onLocationChange)
    12. }, [])
    13. // 找到匹配当前 url 路径的组件并渲染
    14. return routes.find(({ path, component }) => path === currentPath)?.component
    15. }

    和真实的差距:

  • 没法 router 嵌套

    • 监听方式不一样
    • 组件需要缓存

      navigate

      navigate 和 Link:
      相同:
  • 跳转

不同:

  • API:
    • navigate 是调用式函数
    • Link :一个内置 navigate 的 a标签

实现

  1. export function navigate (href) {
  2. // 用 pushState 直接刷新 url,而不触发真正的浏览器跳转
  3. window.history.pushState({}, "", href);
  4. // 手动触发一次 popstate,让 Route 组件监听并触发 onLocationChange
  5. const navEvent = new PopStateEvent('popstate');
  6. window.dispatchEvent(navEvent);
  7. }

刷新 url 后 手动触发 popstate 事件让 Router 控制跳转

Link

  • 首先 Link 本身是一个 a 标签
  • 正常 a 标签点击后会刷新页面而不是单页跳转,所以要先组织 刷新页面这个默认行为
  • 按住 Ctrl 时点击要像正常的 a 一样能新页面跳转

    实现

    1. export function Link ({ className, href, children }) {
    2. const onClick = (event) => {
    3. // mac 的 meta or windows 的 ctrl 都会打开新 tab
    4. // 所以此时不做定制处理,直接 return 用原生行为即可
    5. if (event.metaKey || event.ctrlKey) {
    6. return;
    7. }
    8. // 否则禁用原生跳转
    9. event.preventDefault();
    10. // 做一次单页跳转
    11. navigate(href)
    12. };
    13. return (
    14. <a className={className} href={href} onClick={onClick}>
    15. {children}
    16. </a>
    17. );
    18. };

    参考

    链接