• Vue 通过 Hash、Histroy 实现一个SPA、VueRouter 的简单实现(分享)


    1. 什么是 SPA

    • 之前关于 VueRouter 的文章里写过,这里就不过多叙述了 跳转目标文章

    2. 通过 hash 实现

    2.1 实现思路
    • 改变 url 的 Hash 值,也就是 # 后面的路径
    • 通过 hashchange 来监测变化,做出对应的操作
    2.2 代码实现
    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Hashtitle>
        <style>
          /* 底部区域 */
          footer {
            position: fixed;
            left: 0;
            bottom: 0;
            display: flex;
            justify-content: space-between;
            width: 100%;
          }
    
          footer .box {
            display: flex;
            justify-content: center;
            width: 100px;
            height: 60px;
            text-align: center;
            border: 1px solid #ccc;
            box-sizing: border-box;
          }
    
          footer .box button {
            background-color: white;
            border: none;
            outline: none;
          }
        style>
      head>
      <body>
        <div class="contaienr">
          <div class="content">我是内容区域哈哈哈div>
          <footer>
            <div class="box">
              <button onclick="to('home')">首页button>
            div>
            <div class="box">
              <button onclick="to('mall')">商城button>
            div>
            <div class="box">
              <button onclick="to('shopping')">购物车button>
            div>
            <div class="box">
              <button onclick="to('user')">我的button>
            div>
          footer>
        div>
        <script>
          class MyHash {
            constructor(routes) {
              this.routes = routes;
              this.watchHash();
            }
    
    		// 改变 hash 值
            to(path) {
              location.hash = path;
            }
    
            // 观察 hash 的变化,做出对应操作
            watchHash() {
              window.addEventListener("hashchange", (e) => {
                let { newURL } = e;
                let path = newURL.split("#")[1];
                let { component } = this.routes.find((item) => item.path == path);
                content.innerHTML = component();
              });
            }
          }
    
          let content = document.querySelector(".content");
    
          let myHash = new MyHash([
            {
              path: "home",
              component: () => `

    我是首页

    `
    , }, { path: "mall", component: () => `

    我是商城页

    `
    , }, { path: "shopping", component: () => `

    我是购物车页

    `
    , }, { path: "user", component: () => `

    我是用户页

    `
    , }, ]); function to(path) { myHash.to(path); }
    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
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    3. 通过 history 实现

    3.1 实现思路
    • 在 window 上有一个 history 对象,使用该对象的 pushState、replaceState方法时,对浏览器的历史记录进行操作,页面并不会进行刷新
    • 而使用 history.gohistory.back(工具栏的后退)history.forward(工具栏的前进)时会触发 window 上的 popstate 方法,页面也不会进行刷新
    3.2 代码实现
    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>historytitle>
        <style>
          /* 底部区域 */
          footer {
            position: fixed;
            left: 0;
            bottom: 0;
            display: flex;
            justify-content: space-between;
            width: 100%;
          }
    
          footer .box {
            display: flex;
            justify-content: center;
            width: 100px;
            height: 60px;
            text-align: center;
            border: 1px solid #ccc;
            box-sizing: border-box;
          }
    
          footer .box button {
            background-color: white;
            border: none;
            outline: none;
          }
        style>
      head>
      <body>
        <div class="contaienr">
          <div class="content">我是内容区域哈哈哈div>
          <footer>
            <div class="box"><button onclick="to('home')">首页button>div>
            <div class="box"><button onclick="to('mall')">商城button>div>
            <div class="box"><button onclick="to('shopping')">购物车button>div>
            <div class="box">
              <button onclick="to('user','replaceState')">我的button>
            div>
          footer>
        div>
        <script>
          class MyHistory {
            constructor(routes) {
              this.routes = routes;
              this.watchHistory();
            }
    
            // 由于 pushState 和 replaceState 并不会触发 popState 事件,需要手动监听重写
            rewriteApi(path, type) {
              history[type]({ path }, "", "/" + path);
              this.matchCurRoute(path);
            }
    
            // 监听 go,back,forward
            watchHistory() {
              window.addEventListener("popstate", (e) => {
                this.matchCurRoute(e.state.path);
              });
            }
    
            // 路由发送变化执行对应的操作
            matchCurRoute(path) {
              let { component } = this.routes.find((item) => item.path == path);
              content.innerHTML = component();
            }
          }
    
          let content = document.querySelector(".content");
    
          let myHistory = new MyHistory([
            {
              path: "home",
              // 点击不同的按钮修改内容区域
              component: () => `

    我是首页

    `
    , }, { path: "mall", component: () => `

    我是商城页

    `
    , }, { path: "shopping", component: () => `

    我是购物车页

    `
    , }, { path: "user", component: () => `

    我是用户页

    `
    , }, ]); // 默认是 push function to(path, type = "pushState") { myHistory.rewriteApi(path, type); }
    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
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    4. 效果图

    在这里插入图片描述

  • 相关阅读:
    【vue3+ts后台管理】首页完成
    青少年软件编程C++二级题库(41-50)
    虚幻引擎VS工程代码出现编译 错误 LNK2019 __declspec(dllimport) void __cdecl XXXX(bool)
    yarn : 无法将“yarn”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
    JNI理解学习
    使用tensorflow进行完整的DNN深度神经网络CNN训练完成图片识别案例
    【记一次vsan数据救援的经历】
    React项目实战之租房app项目(五)顶部导航组件封装&CSS Modules解决样式覆盖&地图找房模块封装
    接口---默认方法
    from表单、css选择器、css组合器、字体样式、背景属性、边框设置、display设置
  • 原文地址:https://blog.csdn.net/weixin_60547084/article/details/126504298