前端路由详解

vue:路由实现原理

1  HJAX:hash+ajax实现单页应用,实现无刷新页面更新页面模块,核心api:location、hashchange

特点:

        * 由于路由路径像这样http://localhost:3000#a,由于hash值是完全针对浏览器端的属性,不会传到后端,后端也获取不到hash值,所以不用考虑前、后端路由重合的情况

  // 兼容ie8+和手机端

  // 添加新的历史记录
  location.hash = '#a'

  // 替换当前页面的历史记录
  location.replace('#b')

  // 监听hash的变化
  window.addEventListener('hashchange', function () {
    // 通过location.hash获取相应的hash值,然后处理不同的业务逻辑,切换不同的页面模块
    console.log(location.hash)
  })

2 PJAX:pushState+ajax实现单页应用,实现无刷新页面更新页面模块,核心api:history、popstate

特点:

        * 相对于获取hash值的方法,我们可以自定义state的数据,但是注意通过pushState、replaceState替换路由时,不会触发popstate事件

        * 由于路由路径像这样http://localhost:3000/a,当我们首次在地址栏打开此路径时,会把整个url发送给后端,假如后端没有该路由,那么会报404错误,所以前、后端要协商一下,根据某个关键字来区分是前端路由还是后端路由,如果是前端路由,后端不需要做任何处理

  // 兼容ie10+和手机端

  // 添加新的历史记录
  history.pushState({ url: '/a' }, null, '/a')

  // 替换当前页面的历史记录
  history.replaceState({ url: '/b' }, null, '/b')

  // 监听state的变化
  window.addEventListener('popstate', function () {
    // 通过history.state获取相应的state值,然后处理不同的业务逻辑,切换不同的页面模块
    console.log(history.state)
  })

HJAX简单示例如下(拷贝直接运行):

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  <title>demo</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body,
    html {
      width: 100%;
      height: 100%;
    }

    body {
      height: 1000px;
    }

    .page {
      display: none;
    }
  </style>
</head>

<body>
  <div id="index" class="page">
    <a href="#news">新闻</a>
    <a href="#about">关于</a>
    <p>这是主页</p>
    <p>这是主页</p>
    <p>这是主页</p>
    <p>这是主页</p>
    <p>这是主页</p>
    <p>这是主页</p>
  </div>
  <div id="news" class="page">
    <a href="#index">返回主页</a>
    <p>这是新闻</p>
    <p>这是新闻</p>
    <p>这是新闻</p>
    <p>这是新闻</p>
    <p>这是新闻</p>
    <p>这是新闻</p>
  </div>
  <div id="about" class="page">
    <a href="#index">返回主页</a>
    <p>这是关于</p>
    <p>这是关于</p>
    <p>这是关于</p>
    <p>这是关于</p>
    <p>这是关于</p>
    <p>这是关于</p>
  </div>
</body>
<script>
  class Router {
    constructor() {
      this.init()
    }
    init() {
      this.event().changePage({ hash: location.hash })
    }
    event() {
      const self = this
      // 监听hash变化
      window.addEventListener('hashchange', function () {
        self.changePage({ hash: location.hash })
      })
      return this
    }
    changePage({ hash }) {
      if (!hash) {// 没有路由时,跳至主页
        let indexHash = '#index'
        // 添加一条主页的历史记录
        hash = location.hash = indexHash
      }
      const currentPage = document.querySelector(`#${hash.slice(1)}`)
      // 找不到该路由映射的页面时,不做任何操作
      if (!currentPage) return
      // 隐藏所有的页面
      const allPage = document.querySelectorAll('.page')
      for (let i = 0, len = allPage.length; i < len; i++) {
        allPage[i].style.display = 'none'
      }
      // 显示该路由映射的页面
      currentPage.style.display = 'block'
    }
  }

  const router = new Router()
</script>

</html>

 

Logo

前往低代码交流专区

更多推荐