前端路由原理

为什么要路由?

从前的页面都是多个HTML文件,通过a标签进行跳转。

现代化的框架为了提高可维护性,提出组件化、模块化。

页面的渲染模式变为了 “JS渲染页面”。

页面无法通过url跳转了,因为HTML文件只存在一个,就是首页,其它HTML页面都是不存在的。

就需要一个 路由程序,来控制浏览器地址切换,并展示对应页面组件

路由原理

从上面,我们可以推出,路由的要求

  • 改变路由(但是不刷新页面)。
  • 监听路由。
    • 订阅发布展示内容。

Hash模式

通过hash改变地址,监听hashchange事件,判断hash 展示对应地址内容。

  • 改变路由
    • 浏览器锚点#的变化可以被监听,并且hash改变时不会刷新页面。
  • 监听路由
    • hashchange 事件,可以监听如下变化:
      • 点击 a 标签,改变了浏览器地址。
      • 浏览器的前进后退行为。
      • 通过 window.location 方法,改变浏览器地址。
class Router {
  routes = {}
  currenturl = ''

  route(path, callback = () => void 0) {
    this.routes[path] = callback
  }

  refresh() {
    console.log('触发hashchange')
    const path = location.hash.slice(1) || '/'
    this.currenturl = path
    if ( this.routes[path] ) {
          this.routes[path]()
    }
  }

  init() {
    window.addEventListener('load', () => this.refresh(), false)
    window.addEventListener('hashchange', () => this.refresh(), false)
  }
}
复制代码

缺点:

  • 地址栏,不好看
  • 想服务端发送请求时,锚点不会在url中携带,页面数据不好监控。
  • 锚点功能失效。

History模式

通过url改变地址,监听popstate事件,拦截不触发popstate的跳转方式,判断url展示对应地址内容。

原理:

  • 改变路由
    • historypushState (跳转)和 replaceState (重定向)可以改变地址,并且不刷新页面。
  • 监听路由
    • popstate 事件 ,判断 pathname 地址
      • 浏览器回退,history.back,history.forward都会触发此事件。
    • pushStatereplaceStatea 标签的跳转不会被 popstate 监听。
      • 劫持pushStatereplaceState 方法,内部在调用原方法。
      • a标签
        • 获取全局a标签后添加点击事件
        • 提供Link组件
class JSHistoryRouter {
    constructor(routerview){
        this.routerView = routerview
    }
    init(){
        let that = this
        let linkList = document.querySelectorAll('a[href]')
        linkList.forEach(el => el.addEventListener('click', function (e) {
            e.preventDefault()  // 阻止 <a> 默认跳转事件
            history.pushState(null, '', el.getAttribute('href')) // 获取 URL,跳转
            that.routerView.innerHTML = '当前路由:' + location.pathname
        }))
        // 监听 URL 改变
        window.addEventListener('popstate', ()=>{
            this.routerView.innerHTML = '当前路由:' + location.pathname
        })
    }
    push(path){
        history.pushState(null, '', path)
        this.routerView.innerHTML = '当前路由:' + path
    }
    replace(path){
        history.replaceState(null, '', path)
        this.routerView.innerHTML = '当前路由:' + path
    }
}
复制代码

缺点:

  • 需要nginx做配合,否则会出现404
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享