• 手动实现vue-router


    手动实现vue -router 哈希模式

    实现方式核心在于使用hashchange 事件监听浏览器切换界面请求,更改浏览器地址后渲染新的组件(实际上加#的原因是因为a标签加了#就不会进行页面跳转?)

    a 标签锚点大家应该不陌生,而浏览器地址上 # 后面的变化,是可以被监听的,浏览器为我们提供了原生监听事件 hashchange ,它可以监听到如下的变化:

    • 点击 a 标签,改变了浏览器地址

    • 浏览器的前进后退行为

    • 通过 window.location 方法,改变浏览器地址

      接下来我们利用这些特点,去实现一个hash模式的简易路由

      思路:通过hashchange函数监听路由的变化 切换新的组件

      • html
        • 定义三个元素
          • 两个a标签 (href加上#,阻止默认的跳转行为)
          • 一个类为router-view的div(用于模拟挂载的组件)
      • js
        • 获取id为router-view的元素
        • 定义 HashChange()函数 根据当前的url地址切换需要切换的组件 使用 switch判定切换
    DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Hash 模式title>
    head>
      <body>
        <div>
          <ul>
            <li><a href="#/page1">page1a>li>
            <li><a href="#/page2">page2a>li>
          ul>
          
          <div id="route-view">div>
        div>
      <script type="text/javascript">
        // 第一次加载的时候,不会执行 hashchange 监听事件,默认执行一次
        // DOMContentLoaded 为浏览器 DOM 加载完成时触发
        window.addEventListener('DOMContentLoaded', Load)
        window.addEventListener('hashchange', HashChange)
        // 展示页面组件的节点
        var routeView = null
        function Load() {
          routeView = document.getElementById('route-view')
          HashChange()
        }
        function HashChange() {
          // 每次触发 hashchange 事件,通过 location.hash 拿到当前浏览器地址的 hash 值
          // 根据不同的路径展示不同的内容
          switch(location.hash) {
          case '#/page1':
            routeView.innerHTML = 'page1'
            return
          case '#/page2':
            routeView.innerHTML = 'page2'
            return
          default:
            routeView.innerHTML = 'page1'
            return
          }
        }
      script>
      body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    浏览器展示效果如下:

    c6f4629fc12cd5904e63c04e15b16681.png

    历史模式

    核心在于 popstate事件(在网页回退前进或js手动触发代码时会调用)我们再这个事件调用时触发回调函数,根据当前url切换组件。

    问题在于不是写了这个就行,因为有些事件不会触发这个回调函数,比如a标签的跳转,我们要做的就是,阻值a标签默认动作后,加上点击事件的回调函数,在回调函数内获取 a 标签的 href 属性值,使用pushState、replaceState修改url,再手动触发popstate的回调函数更改显示的组件

    思路:通过popstate事件监听路由的变化 切换新的组件

    • html
      • 定义三个元素
        • 两个a标签 (href加上#,阻止默认的跳转行为)
        • 一个类为router-view的div(用于模拟挂载的组件)
    • js
      • 初始化时 获取所有的a标签元素 进行遍历,添加被点击时的回调函数
        • 阻止默认的页面跳转事件
        • 获取要跳转的地址 手动调用 history.pushState()和history.replaceState()修改url地址 然后调用后面定义的PopChange()函数
      • 获取id为router-view的元素
      • 定义 PopChange()函数 根据当前的url地址切换需要切换的组件 使用 switch判定切换
    DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>History 模式title>
    head>
    <body>
    <div>
     <ul>
       <li><a href="/page1">page1a>li>
       <li><a href="/page2">page2a>li>
     ul>
     <div id="route-view">div>
    div>
    <script type="text/javascript">
     window.addEventListener('DOMContentLoaded', Load)
     window.addEventListener('popstate', PopChange)
     var routeView = null
     function Load() {
       routeView = document.getElementById('route-view')
       // 默认执行一次 popstate 的回调函数,匹配一次页面组件
       PopChange()
       // 获取所有带 href 属性的 a 标签节点
       var aList = document.querySelectorAll('a[href]')
       // 遍历 a 标签节点数组,阻止默认事件,添加点击事件回调函数
       aList.forEach(aNode => aNode.addEventListener('click', function(e) {
         e.preventDefault() //阻止a标签的默认事件
         var href = aNode.getAttribute('href')
         //  手动修改浏览器的地址栏
         history.pushState(null, '', href)
         // 通过 history.pushState 手动修改地址栏,
         // popstate 是监听不到地址栏的变化,所以此处需要手动执行回调函数 PopChange
         PopChange()
       }))
     }
     function PopChange() {
       console.log('location', location)
       switch(location.pathname) {
       case '/page1':
         routeView.innerHTML = 'page1'
         return
       case '/page2':
         routeView.innerHTML = 'page2'
         return
       default:
         routeView.innerHTML = 'page1'
         return
       }
     }
    script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    history

  • 相关阅读:
    Python | Leetcode Python题解之第198题打家劫舍
    类和对象(下)
    Springboot+高校教材预订信息管理系统 毕业设计-附源码150905
    Kubernetes 基础架构最佳实践:从架构设计到平台自动化
    JavaSE_第7章 面向对象基础(下)
    使用 C# / Unity 进行图像处理
    从NetSuite Payment Link杂谈财务自动化、数字化转型
    Visual Studio v1.67改进了深色主题
    自动驾驶技术
    盘点 10 个 GitHub 上的前端高仿项目
  • 原文地址:https://blog.csdn.net/a2274001782/article/details/126230178