首页 > 其他分享 >#yyds干货盘点#History 与 hash

#yyds干货盘点#History 与 hash

时间:2023-12-11 19:32:00浏览次数:22  
标签:yyds return route window location hash History

url 组成

//http://127.0.0.1:8001/01-hash.html?a=100&b=20#/aaa/bbb location.protocal //
'http:' 协议 localtion.hostname // '127.0.0.1' 主机名 location.host //
'127.0.0.1:8001' 主机 location.port //8001 端口号 location.pathname
//'01-hash.html' 访问页面 location.serach // '?a=100&b=20' 搜索内容
location.hash // '#/aaa/bbb' 哈希值

hash 特点

概述

  • hash 本身用于页面定位
  • hash 变化会触发网页跳转,即浏览器的前进和后退。
  • hash 可以改变 url ,但是不会触发页面重新加载(hash 的改变是记录在 window.history 中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http 请求,所以这种模式不利于 SEO 优化。hash 只能修改 # 后面的部分,所以只能跳转到与当前 url 同文档的 url 。
  • hash 通过 window.onhashchange 的方式,来监听 hash 的改变,借此实现无刷新跳转的功能。
  • hash 永远不会提交到 server 端(可以理解为只在前端自生自灭)。

实现前端路由

<!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">page1</a></li>
        <li><a href="#/page2">page2</a></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>

封装

<!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>
      <!-- html:菜单中href设置为hash形式,id为app中放置页面内容 -->
      <ul id="menu">
        <li><a href="#index">首页</a></li>
        <li><a href="#news">资讯</a></li>
        <li><a href="#user">个人中心</a></li>
      </ul>
      <div id="app"></div>
    </div>
    <script type="text/javascript">
      class Router {
        constructor() {
          this.routers = []; //存放我们的路由配置
        }
        add(route, callback) {
          this.routers.push({
            path: route,
            render: callback,
          });
        }
        listen(callback) {
          window.onhashchange = this.hashChange(callback);
          this.hashChange(callback)(); //首次进入页面的时候没有触发hashchange,必须要就单独调用一下
        }
        hashChange(callback) {
          let self = this;
          return function () {
            let hash = location.hash;
            console.log(hash);
            for (let i = 0; i < self.routers.length; i++) {
              let route = self.routers[i];
              if (hash === route.path) {
                callback(route.render());
                return;
              }
            }
          };
        }
      }

      let router = new Router();
      router.add("#index", () => {
        return "<h1>这是首页内容</h1>";
      });
      router.add("#news", () => {
        return "<h1>这是新闻内容</h1>";
      });
      router.add("#user", () => {
        return "<h1>这是个人中心内容</h1>";
      });

      console.log(router);
      router.listen((renderHtml) => {
        let app = document.getElementById("app");
        app.innerHTML = renderHtml;
      });
    </script>
  </body>
</html>

histroy

概述

  • History.length:当前窗口访问过的网址数量(包括当前网页)
  • History.state:History 堆栈最上层的状态值
  • History.back():移动到上一个网址,等同于点击浏览器的后退键。对于第一个访问的网址,该方法无效果。
  • History.forward():移动到下一个网址,等同于点击浏览器的前进键。对于最后一个访问的网址,该方法无效果。
  • History.go():接受一个整数作为参数,以当前网址为基准,移动到参数指定的网址,比如 go(1)相当于 forward()go(-1)相当于 back()。如果参数超过实际存在的网址范围,该方法无效果;如果不指定参数,默认参数为 0,相当于刷新当前页面。
  • History.pushState()方法用于在历史中添加一条记录。该方法接受三个参数,依次为:
  • state:一个与添加的记录相关联的状态对象,主要用于 popstate事件。该事件触发时,该对象会传入回调函数。也就是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面的时候,可以拿到这个对象。如果不需要这个对象,此处可以填 null
  • title:新页面的标题。但是,现在所有浏览器都忽视这个参数,所以这里可以填空字符串。
  • url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
  • pushState()方法不会触发页面刷新,只是导致 History 对象发生变化,地址栏会有反应。
  • 如果 pushState的 URL 参数设置了一个新的锚点值(即 hash),并不会触发 hashchange事件。反过来,如果 URL 的锚点值变了,则会在 History 对象创建一条浏览记录。
  • 如果 pushState()方法设置了一个跨域网址,则会报错。
  • History.replaceState()方法用来修改 History 对象的当前记录,其他都与 pushState()方法一模一样
  • popstate 事件,每当同一个文档的浏览历史(即 history对象)出现变化时,就会触发 popstate事件。
  • 注意,仅仅调用 pushState()方法或 replaceState()方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用 JavaScript 调用 History.back()History.forward()History.go()方法时才会触发。另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。
window.onpopstate = function (event) {
  console.log("location: " + document.location);
  console.log("state: " + JSON.stringify(event.state));
};

// 或者
window.addEventListener("popstate", function (event) {
  console.log("location: " + document.location);
  console.log("state: " + JSON.stringify(event.state));
});

实现前端路由(需要项目启动)

<!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">page1</a></li>
    <li><a href="/page2">page2</a></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>

封装

<!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>
  <!-- html:菜单中href设置为hash形式,id为app中放置页面内容 -->
  <ul id="menu">
    <li><a href="/index">首页</a></li>
    <li><a href="/news">资讯</a></li>
    <li><a href="/user">个人中心</a></li>
  </ul>
  <div id="app"></div>
</div>
<script type="text/javascript">
  class Router {
    constructor() {
      this.routers = [];
      this.renderCallback = null;
    }
    add(route, callback) {
      this.routers.push({
        path: route,
        render: callback,
      });
    }
    pushState(path, data = {}) {
      window.history.pushState(data, "", path);
      this.renderHtml(path);
    }
    listen(callback) {
      this.renderCallback = callback;
      this.changeA();
      window.onpopstate = () => this.renderHtml(this.getCurrentPath());
      this.renderHtml(this.getCurrentPath());
    }
    changeA() {
      document.addEventListener("click", (e) => {
        if (e.target.nodeName === "A") {
          e.preventDefault();
          let path = e.target.getAttribute("href");
          this.pushState(path);
        }
      });
    }
    getCurrentPath() {
      return location.pathname;
    }
    renderHtml(path) {
      for (let i = 0; i < this.routers.length; i++) {
        let route = this.routers[i];
        if (path === route.path) {
          this.renderCallback(route.render());
          return;
        }
      }
    }
  }

  let router = new Router();
  router.add("/index", () => {
    return "<h1>这是首页内容</h1>";
  });
  router.add("/news", () => {
    return "<h1>这是新闻内容</h1>";
  });
  router.add("/user", () => {
    return "<h1>这是个人中心内容</h1>";
  });
  router.listen((renderHtml) => {
    let app = document.getElementById("app");
    app.innerHTML = renderHtml;
  });
</script>
</body>


## 参考

https://juejin.cn/post/6993840419041706014
https://cloud.tencent.com/developer/article/1904982
https://wangdoc.com/javascript/bom/history

标签:yyds,return,route,window,location,hash,History
From: https://blog.51cto.com/u_11365839/8777201

相关文章

  • 【Java集合】双列集合HashMap的概念、特点及使用
    上篇文章讲了Map接口的概念,通过他提供的接口方法,我们学习了如何使用以及对Map集合的遍历HashMap概念HashMap集合是Map接口的一个实现类,它用于存储键值映射关系,该集合的键和值允许为空,但键不能重复,且集合中的元素是无序的。特点HashMap底层是由哈希表结构组成的,其实就是“数组......
  • # yyds干货盘点 # 盘点一个Pandas处理Excel表格实战问题(下篇)
    大家好,我是皮皮。一、前言继续接着上一篇文章说,这一篇文章我们一起来看看大佬们的解决办法。二、实现过程这里【郑煜哲·Xiaopang】和【瑜亮老师】给了一个提示,如下图所示:后来【隔壁......
  • day18 hash logging模块
    day182023年12月9日周六14:03:43day17复习datetime.datetime.now()要什么文件切割就可以random.choice([1,2,3])随机选择random.shuffle()打乱顺序random.random(1,2)随机取数os.mkdir()新建一个文件夹os模块与操作系统交互操作文件和文件夹sys与py解释器交互环境变量......
  • #yyds干货盘点#深入了解Python类与面向对象编程
    类与对象的概念1.什么是类?类是一种用户自定义的数据类型,用于描述对象的属性和行为。它是对象的模板,定义了对象的结构。2.创建类使用class关键字来创建类。示范如何定义一个类,包括类名、属性和方法的定义。classDog:def__init__(self,name,breed):self.name=nam......
  • 【JavaSE】集合Collection{List(ArrayList, LinkedList), Set(TreeSet, HashSet, Link
    集合单列集合:Collection接口单列集合:一次添加一个元素;如果集合中添加的是类,要重写equals方法,否则比较的是地址,无法正常删除内容相同的元素。单列集合通用遍历方式1.迭代器遍历2.增强for循环遍历增强for循环底层逻辑还是迭代器,字节码文件反编译为java会发现还是迭代......
  • 【JavaSE】数据结构-哈希表(HashSet/HashMap底层哈希表详解,源码分析)
    哈希表结构JDK8版本之前:数组+链表JDK8版本及之后:数组+链表+红黑树哈希表HashMapput()方法的添加流程创建HashSet集合时,构造方法中自动创建HashMap集合;HashMap空参构造方法会创建一个默认长度为16,默认加载因子为0.75的数组,数组名为table(tips:实际上,HashSet对象创建后,第......
  • JavaScript-history对象
    概述window.history属性指向History对象,它表示当前窗口的浏览历史。History对象保存了当前窗口访问过的所有页面网址。下面代码表示当前窗口一共访问过3个网址。window.history.length//3由于安全原因,浏览器不允许脚本读取这些地址,但是允许在地址之间导航。//后退到前一个网......
  • flask支持Vue2 mode history历史模式
    VueRouter配置在Vue2router里面增加constrouter=newVueRouter({mode:'history',base:'/admin/',//这里路径写你打包后的网址路径routes:[//这里是你的路由配置],});vue.config.js打包配置const{defineConfig}=require('@vue/cli-service......
  • #yyds干货盘点#Java面试题
    1.如何理解面向对象和面向过程【面向过程】:完成某件事的过程,性能高于【面向对象】优点:但是因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。缺点:没有面向对象易维护、易复用、易扩展【面向对象】:把要完......
  • Python的hashlib模块
    一、什么是摘要算法1、摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)用于生成数据或文本的简短摘要或哈希值的算法。它们被广泛应用于密码学、数据完整性验证和信息检索等领域。摘要算法通过对输入数据进......