【javascript】hash路由和browser路由原理

前言

  • spa路由原理还是很有意思的,实际上是就是浏览器提供的api接口,但这个接口还有些缺陷,但是可以允许我们对其进行重新改写。

hash路由

  • 哈希路由就是路由上面有个#,以前是用来做锚点的,很多人可能会想知道这个hash路由和锚点到底有啥区别?
  • 锚点实际上是通过#后面的东西来跳到对应相同id的元素。
  • 而哈希路由是监听这个哈希路由改变的事件,渲染相对应的页面元素。
  • 那么问题来了,2者是同时起效还是有一个不起作用还是根本就冲突?
  • 答案是都会起效。可以拿下面这个例子验证:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
    <body>
      <a href="#/a">去/a</a>
      <a href="#/b">去/b</a>
      <div id="root"></div>
      <div style="height: 1000px;"></div>
      <div id="/b">231</div>
      <script>
        let root = document.getElementById('root');
        window.addEventListener('hashchange', (event) => {
          let hash = window.location.hash;// #/a #/b
          root.innerHTML = hash;
        });
      </script>
    </body> 
 </html>
  • 验证可以发现,页面跳向锚点231的同时,也把挂在root的元素给渲染出来了。
  • 可能有人觉得有个/不是传统锚点写法,实际验证去了/也是同时触发。
  • 另外查看hash可以调用window.location.hash,如果给这个赋值,最开始的井号可以写也可以不写,对应的是一个哈希。也就是#/a/a是一个路径,路径上都会写成#/a

browser路由

  • browser路由主要是靠对window.history的操作。这个api有个特点,就是往history里push路由,会跳到相应路由,但没有监听函数,而回退操作却有监听函数。
  • 由于没有push监听函数,所以可以对其进行改写:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
    <body>
        <div id="root"></div>
        <script>
          let root = document.getElementById('root');
          
          //加入一个自己写的方法
          window.onpushstate = function (state, title, url) {
            console.log({ type: 'onpushstate', state, pathname: url });
            root.innerHTML = url;
          };

          //改写pushState方法,让其调用会执行自己写的方法,再执行它原本方法。
          (function (history) {
            let pushState = history.pushState;//在自执行函数缓存旧的pushState方法
            history.pushState = function (state, title, url) {
              if (typeof window.onpushstate == 'function') {
                window.onpushstate(state,title, url);
              }
              return pushState.apply(history, arguments);
            }
          })(window.history);
          
          //回退会触发监听,而push没有监听所以只能改写。
          window.onpopstate = function (event) {
            console.log({ type: event.type, state: event.state, pathname: window.location.pathname });
            root.innerHTML = window.location.pathname;
          }
          setTimeout(() => {
            window.history.pushState({ page: 1 }, 'page1', '/page1');
          }, 1000);
          setTimeout(() => {
            window.history.pushState({ page: 2 }, 'page2', '/page2');
          }, 2000);
          setTimeout(() => {
            window.history.pushState({ page: 3 }, 'page3', '/page3');
          }, 3000);
          setTimeout(() => {
            window.history.go(-1);
          }, 4000);
        </script>
    </body>
    </html>
  • 另外可以看见,window.history.pushState第一个参数时data,第二个参数是title,第三个是url,所以browserRouter可以携带状态信息去下一个路由,这样对权限判断之类提供了便捷,而这个地方也是跟哈希路由最大的区别。
  • 当然可能有人会重写hash路由的方法让其带有信息,这就不在讨论范围内了。
发布了163 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/yehuozhili/article/details/103866567