前端路由与单页页面实践

IT科技2025-11-04 07:15:516792

​​想了解更多内容,前端请访问:​​

​​和华为官方合作共建的单页鸿蒙技术社区​​

​​https://ost.51cto.com​​

路由就是指随着浏览器地址栏的变化,展示给用户的页面页面也不相同。

传统的实践网页根据用户访问的不同的地址,浏览器从服务器获取对应页面的前端内容展示给用户。这样容易造成服务器压力比较大,单页而且用户访问速度也比较慢,页面在这种场景下,实践出现了单页应用。前端

路由的单页实现方式location.hash+hashchange事件。history.pushState()+popState事件。页面实现主要基于以下几个方面的实践特性URL 中的 hash 值只是客户端的一种状态,也就是前端说当向服务器发出请求时,hash 部分不会被发送。单页hash 值的页面改变,都会在浏览器的访问历史中增加一个记录,因此我们能通过浏览器的回退,企商汇前进按钮控制 hash 的切换。可以通过设置a标签,并通过设置 href 属性,例如href = ‘#/blue’,当点击标签的时候,url的 hash 。值会发生改变,在当前url的后面增加上’#/blue’, 同时触发hashchange,再回调函数中进行处理。前进后退的时候,可以直接通过js来对 location.hash 进行赋值,改变url的 hash 值,例如 location.hash = ‘#/blue’即可,此时url会改变, 也会触发hashchange事件。因此我们可以使用 hashchange 事件来监听 hash 值得变化,从而对页面进行跳转(渲染)。hash模式

hash方法是在路由中带有一个#,主要原理是通过监听#后的 URL 路径标识符的更改而触发的浏览器hashchange事件,然后通过获取location.hash 得到当前的路径标识符,再进行一些路由跳转的WordPress模板操作。hash方法的push本身会记录你的点击记录,当你想要通过返回按钮返回时,它会根据你的点击记录用到replace来解决。

先建立一个index.html文件,在body标签中开始hash的编写:

// index.html

前端路由

hello , Hash router!!!

  • turn white
  • turn blue
  • turn green
  • turn red
  • turn orange
  • function render() {

    app.innerHTML = 渲染容器 + window.location.hash;

    app.style.backgroundColor = "pink"

    }

    window.addEventListener(hashchange, render)

    </html>

    然后引用js文件处理router里面的逻辑:

    // hash.js

    class Router {

    constructor() {

    /

    **

    * 以键值对的形式存储路由

    */

    this.routers = new Object();

    /

    **

    * 当前路由的URL

    */

    this.currentUrl = "";

    /

    **

    * 记录出现过的hash

    */

    this.history = [];

    /

    **

    * 作为指针,默认指向this.history的末尾,根据后退前进指向history中不同的hash

    */

    this.currentIndex = this.history.length - 1;

    /

    **

    * 默认不是后退操作

    */

    this.isBack = false;

    }

    /

    **

    * 都定义在原型上,后面的覆盖前面的,这个不执行

    */

    route(path, callback) {

    console.log(1);

    }

    }

    /

    **

    * 将路由的hash以及对应的callback函数储存

    * @param path

    * @param callback

    */

    Router.prototype.route = function (routes) {

    for (let route of routes) {

    this.routers[route.path] = route.callback || function () { };

    }

    };

    /

    **

    * 当页面刷新的时候

    */

    Router.prototype.refresh = function () {

    /

    **

    * 获取当前页面中的hash路径

    */

    this.currentUrl = window.location.hash.slice("1") || "/";

    /

    **

    * 不是后退才执行

    */

    if (!this.isBack) {

    if (this.currentIndex < this.history.length - 1)

    this.history = this.history.slice(0, this.currentIndex + 1);

    /

    **

    * 将当前hash路由推入数组储存,指针向前移动

    */

    this.history.push(this.currentUrl);

    this.currentIndex++;

    }

    this.isBack = false;

    /

    **

    * 执行当前hash路径的回调函数

    */

    this.routers[this.currentUrl]();

    console.log("refresh");

    console.log(this.history);

    console.log(this.currentIndex);

    };

    /

    **

    * 当页面后退,回退的过程中会触发hashchange,将hash重新放入,索引增加

    */

    Router.prototype.back = function () {

    console.log("back");

    console.log(this.history);

    console.log(this.currentIndex);

    // 后退操作设置为true

    this.isBack = true;

    /

    **

    * 如果指针小于0的话就不存在对应hash路由了,因此锁定指针为0即可

    */

    this.currentIndex <= 0

    ? (this.currentIndex = 0)

    : (this.currentIndex = this.currentIndex - 1);

    /

    **

    * 随着后退,location.hash也应该随之变化

    * 并执行指针目前指向hash路由对应的callback

    */

    location.hash = `#${this.history[this.currentIndex]}`;

    this.routers[this.history[this.currentIndex]]();

    };

    /

    **

    * 初始化,监听页面的加载与hash值的b2b信息网变化

    */

    Router.prototype.init = function () {

    /

    **

    * 修改this指向,否则指向window

    */

    window.addEventListener("load", this.refresh.bind(this), false);

    window.addEventListener("hashchange", this.refresh.bind(this), false);

    };

    // 监听hash模式路由

    Router.prototype.eventHashRouter = function() {

    // 监听load事件,防止刷新页面数据丢失

    window.addEventListener("load", this.hashRouter.bind(this));

    window.addEventListener("hashchange", this.hashRouter.bind(this))

    }

    //replace模式页面跳转

    Router.prototype.replace = function(url) {

    url = "#" +url;

    window.location.replace(url);

    }

    const route = new Router();

    /

    **

    * 初始化

    */

    route.init();

    const routes = [

    {

    path: "/",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "#fff";

    },

    },

    {

    path: "/blue",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "blue";

    },

    },

    {

    path: "/green",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "green";

    },

    },

    {

    path: "/red",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "red";

    },

    },

    {

    path: "/orange",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "orange";

    },

    },

    ];

    /

    **

    * 将hash值与cb绑定

    */

    route.route(routes);

    window.onload = function () {

    let btn = document.getElementById("btn");

    btn.addEventListener("click", route.back.bind(route), false);

    };history模式

    HistoryAPI来实现URL的变化,其中最主要用history.pushState()新增一个历史记录,用history.replaceState()直接替换当前历史记录,可以在不进行刷新的情况下,操作浏览器的历史记录。需要后台配置支持,因为我们的应用是个单页的客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问一些没有配置的路径就会返回404,但因为没有#号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要定向到根路径。html5 提供了historyAPI来实现URL的变化,其中最主要的 API 有以下两个:

    history.pushState()新增一个历史记录。history.replaceState()直接替换当前历史记录。相同点:

    可以在不进行刷新的情况下,操作浏览器的历史记录。先建立一个index.html文件,在body标签中开始history的编写:

    前端路由

    hello , History router!!!

  • turn white
  • turn blue
  • turn green
  • turn red
  • turn orange
  • function handleClick(e) {

    // e.target.href = "/color/blue"

    // console.log(this.location.host);

    }

    </html>

    然后引用js文件处理router里面的逻辑:

    // history.js

    /

    **

    * history路由

    */

    class Router {

    constructor() {

    /

    **

    * 以键值对的形式存储路由

    */

    this.routers = new Object();

    }

    }

    /

    **

    * 监听页面的popstate事件

    */

    Router.prototype.bindPopState = function (e) {

    const path = e.state && e.state.path;

    this.routers[path] && this.routers[path]();

    };

    /

    **

    * 将路由的path以及对应的callback函数储存

    * @param path

    * @param callback

    */

    Router.prototype.route = function (routes) {

    for (let route of routes) {

    this.routers[route.path] = route.callback || function () { };

    }

    };

    /

    **

    * 初始化,直接替换当前历史纪录,并用状态对象进行存储

    */

    Router.prototype.init = function (path) {

    window.history.replaceState({ path: path }, null, path);

    this.routers[path] && this.routers[path]();

    /

    **

    * 加入事件监听

    */

    window.addEventListener("popstate", this.bindPopState.bind(this), false);

    };

    /

    **

    * 更新页面,新增一个历史纪录

    */

    Router.prototype.go = function (path) {

    window.history.pushState({ path: path }, null, path);

    this.routers[path] && this.routers[path]();

    };

    const route = new Router();

    route.init(window.location.href);

    const routes = [

    {

    path: "http://127.0.0.1:5500/",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "#fff";

    },

    },

    {

    path: "http://127.0.0.1:5500/color/blue",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "blue";

    },

    },

    {

    path: "http://127.0.0.1:5500/color/green",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "green";

    },

    },

    {

    path: "http://127.0.0.1:5500/color/red",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "red";

    },

    },

    {

    path: "http://127.0.0.1:5500/color/orange",

    callback: function () {

    let el = document.body;

    el.style.backgroundColor = "orange";

    },

    },

    ];

    /

    **

    * 将hash值与cb绑定

    */

    route.route(routes);

    /

    **

    * a标签会跳转页面,阻止

    */

    window.addEventListener(

    "click",

    function (e) {

    var e = e || window.event;

    var target = e.target || e.srcElement;

    if ((target.tagName = "A")) {

    e.preventDefault();

    route.go(e.target.getAttribute("href"));

    }

    },

    false

    );总结

    本文讲解了路由的核心实现原理,但是结合具体框架后,框架增加了很多特性,如动态路由、路由参数、路由动画等等,这些导致路由实现变的复杂。本文去粗取精只针对前端路由最核心部分的实现进行分析,并基于 hash 和 history 两种模式,页面加载时,它可能有一个非空状态对象。例如,如果页面设置了一个状态对象(使用pushState()or replaceState())然后用户重新启动他们的浏览器,当页面重新加载时,页面将收到一个onload事件,虽没有popstate事件,但是将获得加载的状态对象。

    ​​想了解更多内容,请访问:​​

    ​​和华为官方合作共建的鸿蒙技术社区​​

    ​​https://ost.51cto.com​​

    本文地址:http://www.bzuk.cn/html/044a31799638.html
    版权声明

    本文仅代表作者观点,不代表本站立场。
    本文系作者授权发表,未经许可,不得转载。

    全站热门

    电脑word文档教程表格的使用方法(掌握word表格的关键技巧,轻松编辑文档)

    好家伙,这些写 CSS 的新姿势你还不知道?

    给女同事讲完代理后,女同事说:你好棒哦

    性能分析不一定得用 Profiler,复杂度分析也行

    如何去掉Word文档中的空白页?(简单有效的方法帮助您轻松处理Word文档中的无用空白页)

    推荐系统的数据源与数据预处理

    用这个Python的Docker正式版镜像,你也能成容器高玩

    原来一个 Map 就能搞定注册表了

    友情链接

    滇ICP备2023006006号-33