前端路由的实现

208 阅读2分钟

前端路由的概念

路由的概念是服务器上,URL和处理函数的映射关系

  • 前段路由在单页应用中体现,描述的是URL和UI页面的映射关系,即URL变了 —— UI更新(无需刷新页面)

如何实现前端路由

这里有俩个问题:

  1. 如何改变URL却不影响页面的刷新?
  2. 如何检测到URL变化了?

解决方法:

1. hash实现

  1. hash是URL中 # 后面的那一部分,改变URL中的hash,页面不刷新,在#后面拼接url地址,这就解决了问题一。
  2. hashchange 用于监听页面的hash值发生变化,只要页面的url发生变化这个函数就会触发。这是原生js提供的方法。第二个问题就得到了解决。

接下来我们看一个例子的核心代码:

要求:在页面上定义两个a标签,点击标签跳转时显示对应的页面内容,并且页面不发生刷新。

<body>
  <ul>
    <li><a href="#/home">home</a></li>
    <li><a href="#/about">about</a></li>
  </ul>

  <div id="routerView"></div>
  <script>
    //拿到dom结构
    var routerView = document.getElementById('routerView')
    
    //监听dom结构加载完毕后,就先调用一次
    window.addEventListener('DOMContentLoaded',onHashChange)

    //hashchange 监听URL发生变化
    window.addEventListener('hashchange',onHashChange)
    function onHashChange(){
      //获取当前浏览器的URL
      console.log(location.hash);
      switch(location.hash){  //匹配对应url的页面内容
        case '#/home':routerView.innerHTML = 'Home page' 
        return
        case '#/about' : routerView.innerHTML = 'About page'
         return
         default:
          return 

      }
    }
  </script>
</body>

实现效果:

QQ录屏20220419171911.gif 我们可以看到当该改变url后显示出了对象的页面内容,并且页面没有发生刷新。

2. hsitory

  1. history是HTML提供的一个对象,其中提供了pushStatereplaceShashchangetate 俩个方法,这俩个方法都可以改变URL且不引起页面刷新。也提供了一个popstate方法,作用和hashchange类似。
  2. pushStatereplaceState的调用 和 a标签的点击事件是可以被拦截的。其原理就是拦截下来a标签的点击事件,并让其href属性不生效,达到页面不刷新的效果。

跟上面同样的例子:

<body>
  <ul>
    <li><a class="link1" href="/home">home</a></li>
    <li><a class="link2" href="/about">about</a></li>
  </ul>

  <div id="routerView"></div>
  
<script>

  //只要是用pushState 或 replaceState 让url变化的 就会被监听到
  window.addEventListener('popstate',onPopState)

//拿到当前页面路径并匹配对应页面
 function onPopState(){
   switch(location.pathname){
    case '/home':
    routerView.innerHTML = '<h2>Home</h2>'
    return 
    case '/about':
    routerView.innerHTML = '<h2>About</h2>'
    return 
    default:
    return 
   }
 }

//页面dom结构加载完成之后,调用onload
window.addEventListener('DOMContentLoaded',onLoad)

 function onLoad(){
  var routerView = document.getElementById('routerView')

  //拦截a标签的点击事件
  var linkList = document.querySelectorAll('ul li a')
  linkList.forEach(el =>{
    el.addEventListener('click',function(e){
      //阻止默认事件
      e.preventDefault();

     //用pushState 或 replaceState手动修改URL
     history.pushState(null,'',el.getAttribute('href'))
    })
  })
 }

</script>
</body>

这个过程就是拿到a标签,禁用掉其默认跳转事件,然后通过 pushStatereplaceState手动修改要跳转的地址,popstate就会监听到,最后对应url渲染页面内容。

实现效果:

history.gif