前端路由+原生JS实现SPA

news2024/12/23 10:28:04

 

●前端路由
●路由: 就是一一对应关系的集合
●前端路由: 就是一个 url 地址, 对应哪个组件(页面)
●前端路由的本质
○根据地址栏变化(不重新想服务器发送请求), 去局部更新不同的页面内容, 完成前端业务场景切换
●前端路由的思路
○URL 地址栏中的 Hash 值发生了变化
○前端 JS 监听到 Hash 地址的变化 window.onhashchange = () => {}
○前端 JS 把当前 Hash 地址对应的组件渲染到浏览器中
●SPA
○ 单页面应用 (single page application)
○就是只有一张 Web 页面的应用, 是加载单个 HTML 页面并在用户与应用程序交互时, 动态更新该页面的 Web 应用程序
简单实现

<!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>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        html,
        body,
        .box {
            width: 100%;
            height: 100%;
        }

        .box {
            display: flex;
            flex-direction: column;
        }

        .box>.top {
            width: 100%;
            height: 100px;
            background-color: brown;
            font-size: 30px;
            line-height: 100px;
            text-align: center;
        }

        .box>.bottom {
            flex: 1;
            display: flex;
        }

        .box>.bottom>.slide {
            width: 230px;
            background-color: aqua;
            box-sizing: border-box;
            padding: 15px;
            font-size: 25px;
        }

        .box>.bottom>.slide>a {
            display: block;
            margin: 10px 0;
        }

        .box>.bottom>.content {
            width: 100%;
            background-color: coral;
            box-sizing: border-box;
            padding: 15px;
            font-size: 20px;
        }
    </style>
</head>

<body>
    <div class="box">
        <div class="top"> 顶部通栏 </div>
        <div class="bottom">
            <div class="slide">
                <a href="#/pageA">pageA</a>
                <a href="#/pageB">pageB</a>
                <a href="#/pageC">pageC</a>
                <a href="#/pageD">pageD</a>
            </div>
            <div class="content router-view">内容区</div>
        </div>
    </div>
    <script>
        // 准备一些渲染内容, 后续会根据 Hash 值去展示
        const templateA = `<div>templateA</div>`
        const templateB = `<div>templateB</div>`
        const templateC = `<div>templateC</div>`
        const templateD = `<div>templateD</div>`
        
        // 获取 Dom 节点
        const rw = document.querySelector('.router-view')
        
        // 监听 hash 值的变化
        window.onhashchange = function () {
            // 这个函数执行, 表明hash锚点发生变化, 将内容区的文本切换为对应的文本
            console.log(window.location.hash)
            const { hash } = window.location    // 相当于: const hash = window.loaction.hash
            
            // 根据当前的 Hash 值, 决定渲染哪一段内容
            if (hash === '#/pageA') {
                rw.innerHTML = templateA
            } else if (hash === '#/pageB') {
                rw.innerHTML = templateB
            } else if (hash === '#/pageC') {
                rw.innerHTML = templateC
            } else if (hash === '#/pageD') {
                rw.innerHTML = templateD
            }
        }
    </script>
</body>

</html>


复制代码

文章底部扫码,免费领取前端资料大礼包!

●当前所有的 展示内容, 都书写在了 这个 HTML 文件中, 这种写法在简单案例中没有什么不妥, 但是如果在实际开发中肯定不好
●因为每一个 展示的内容代码量都可能有很多, 所以放在一个文件内部会影响阅读体验, 所以我们可以将代码重新整理调整一下结构
代码结构调整
●SPA/components/templateA.js

const temAHtml = `<div id="pageA">pageA_template</div>`;
const routerView = document.querySelector('.router-view')
function rander () {
    routerView.innerHTML = temAHtml
}
export default rander


复制代码

●SPA/components/templateB.js


const temBHtml = `<div id="pageB">pageB_template</div>`;
const routerView = document.querySelector('.router-view')
function rander () {
    routerView.innerHTML = temBHtml
}
export default rander


复制代码

●SPA/components/templateC.js

const temCHtml = `<div id="pageC">pageC_template</div>`;
const routerView = document.querySelector('.router-view')
function rander () {
    routerView.innerHTML = temCHtml
}
export default rander


复制代码

● SPA/components/templateD.js


const temDHtml = `<div id="pageD">pageD_template</div>`;
const routerView = document.querySelector('.router-view')
function rander () {
    routerView.innerHTML = temDHtml
}
export default rander


复制代码

文章底部扫码,免费领取前端资料大礼包!

●SPA/router.js


// 按照策略模式组装一个路由表
import temA from "./components/templateA.js";
import temB from "./components/templateB.js";
import temC from "./components/templateC.js";
import temD from "./components/templateD.js";

const router = [
    {
        name: "/pageA",
        compoment: temA,
    },
    {
        name: "/pageB",
        compoment: temB,
    },
    {
        name: "/pageC",
        compoment: temC,
    },
    {
        name: "/pageD",
        compoment: temD,
    },
    {
        // 如果当前的 路由是 /, 那么就重定向到 /pageA
        name: "/",
        redirect: "/pageA",
    },
];

// 导出路由表
export default router;


复制代码

●SPA/index.js


// 1. 导入路由表
import router from "./router.js";

// 注册 hash 改变事件
window.onhashchange = function () {
    const hash = window.location.hash.slice(1);
    const info = router.find((t) => t.name === hash);
    info.compoment();
}


复制代码

●SPA/index.html


<!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>Document</title>
    <style>
        /* 一堆 CSS 代码, 与简单实现时一样, 这里不做重复书写 */
    </style>
</head>

<body>
    <div class="box">
        <div class="top"> 顶部通栏 </div>
        <div class="bottom">
            <div class="slide">
                <a href="#/pageA">pageA</a>
                <a href="#/pageB">pageB</a>
                <a href="#/pageC">pageC</a>
                <a href="#/pageD">pageD</a>
            </div>
            <div class="content router-view"></div>
        </div>
    </div>

    <!-- 注意使用模块发的方式导入文件 -->
    <script src="./index.js" type="module"></script>
</body>

</html>


复制代码

文章底部扫码,免费领取前端资料大礼包!

路由重定向
●路由重定向
○ 我们当前的的单页应用整体没什么大问题, 但是有一个小问题是首次进入页面的时候, 渲染区没有内容展示
○我们的解决方式也很简单, 就是在首次进入的时候, 将我们的路由重定向到 '/pageA'
○这样的话我们在首次进入页面的时候就能够展示出对应的内容
➢SPA/index.js


// 1. 导入路由表
import router from "./router_b.js";
// 注册 hash 改变事件
window.onhashchange = hashChangeHandler;
hashChangeHandler();
function hashChangeHandler() {
    // 首次进入页面的时候 hash 值为空字符, 默认给一个 '/'
    const hash = window.location.hash.slice(1) || "/";
    
    const info = router.find((t) => t.name === hash);

    // 路由表中 重定向的优先级最高
    if (info.redirect) return (window.location.hash = info.redirect);

    info.compoment();
}


复制代码

➢SPA/router.js


import temA from "./components/templateA.js";
import temB from "./components/templateB.js";
import temC from "./components/templateC.js";
import temD from "./components/templateD.js";

const router = [
    {
        name: "/pageA",
        compoment: temA,
    },
    {
        name: "/pageB",
        compoment: temB,
    },
    {
        name: "/pageC",
        compoment: temC,
    },
    {
        name: "/pageD",
        compoment: temD,
    },
    {
        // 如果当前的 路由是 /, 那么就重定向到 /pageA
        name: "/",
        redirect: "/pageA",
    },
];

// 导出路由表
export default router;


复制代码

懒加载
●现在的问题是在我们当前的完成方式中
○首先会去运行 index.html
○运行时会以模块化的方式引入 index.js
○在 index.js 中, 我们我们在代码开始, 导入了 router.js
○此时引入导入的特性, 会将 router.js 中的代码全都执行一次
○而在 router.js 中, 我们又导入了 components 中的 四个文件
○所以也会把这四个文件的内容全都执行一遍, 哪怕有些文件在首次执行的时候并没有使用到
●所以此时出现了一个问题
○假如我 router.js 中有 200 个文件, 而我首次渲染的时候只用到了其中一个
○但是我们现在的写法, 在首次运行时仍然会将我 没用到的那 199 个文件, 都运行一遍
○有一种更好的方式就是我用到了什么文件, 你再加载什么文件即可, 所以我们现在需要使用 "懒加载" 来解决
●换句话说, 懒加载其实就是, 用到了那个文件, 我在加载那个文件, 而不是在开始的时候, 一股脑的全加载完
●方式也很简单, 我们首先是需要调整一下引入的方式
○语法; import('地址')
○注意: 这种引入方式是按照 promise 的语法封装的函数
○返回值: 因为使用 promise 封装的, 所以他的返回值不是我们默认导出的内容, 而是一个 promise 对象
○所以我们的 index.js 也需要适当的调整

➢SPA/router.js


const router = [
    {
        name: "/pageA",
        compoment: () => import("./components/templateA.js"),
    },
    {
        name: "/pageB",
        compoment: () => import("./components/templateB.js"),
    },
    {
        name: "/pageC",
        compoment: () => import("./components/templateC.js"),
    },
    {
        name: "/pageD",
        compoment: () => import("./components/templateD.js"),
    },
    {
        // 如果当前的 路由是 /, 那么就重定向到 /pageA
        name: "/",
        redirect: "/pageA",
    },
];

// 导出路由表
export default router;



复制代码

文章底部扫码,免费领取前端资料大礼包!

➢SPA/index.js


// 1. 导入路由表
import router from "./router_b.js";

// 注册 hash 改变事件
window.onhashchange = hashChangeHandler;
hashChangeHandler();
function hashChangeHandler() {
    const hash = window.location.hash.slice(1) || "/";
    const info = router.find((t) => t.name === hash);

    // 路由表中 重定向的优先级最高
    if (info.redirect) return (window.location.hash = info.redirect);

    // 调用 component 的到一个返回值, 如果是普通引入, 那么这里一定是 undefined, 我们直接 return 即可
    const res = info.compoment();
    if (res === undefined) return;

    // 代码能运行到这里说明我们 调用 component 得到的是一个 promise 对象, 所以我们可以通过 then 方法以及他的参数去调用我们实际导出的内容
    res.then((result) => result.default());
}

更多精彩教程欢迎B站搜索“千锋教育

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/531602.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[JAVA] 图书管理系统

前言 1. 基本情况 2. 基本思路 3. 类的创建 Book包底下类有实现 &#xff08;1&#xff09;Book类 - 图书类 &#xff08;2&#xff09;BookList - 书架类 operation包底下类的实现(包含7个类,一个接口) &#xff08;1&#xff09;IOperation接口 - 功能接口 &…

蓝精灵协会每周社区会议|延长水晶铸造期限以及游戏重启计划

蓝精灵协会每周社区会议来啦&#xff01;我们已经把活动名称从「AMA」改为「市政会议厅」&#xff0c;因为该会议的目的是倾听社区反馈和进行讨论。当然&#xff0c;我们仍然非常欢迎你提出问题&#xff01; 本次市政会议厅涵盖四个主题&#xff1a; 延长水晶铸造时间的投票结果…

scrollIntoView的基本定义、以及Vue3、vue2中使用: 点击导航滚动到对应区域。

1. 基本定义 MDN 关于scorllIntoView的介绍 Element 接口的 scrollIntoView() 方法会滚动元素的父容器&#xff0c;使被调用 scrollIntoView() 的元素对用户可见。 scrollIntoView()scrollIntoView(alignToTop)scrollIntoView(scrollIntoViewOptions) 1. alignToTop 可选 alig…

aws Automation

In order to save money, CloudFormation terminates the resources from the template Systems Manager will handle on-premises and EC2 instance patches Caching Amazon CloudFront 是一种内容分发网络 (CDN) 服务&#xff0c;旨在获得优异性能、安全性和开发人员便利性…

A股市场上股票行情数据接口有那几种?

L2行情数据接口相比Level-1接口相比&#xff0c;L2行情市场具有数据更完整、推送速度更及时的优势&#xff0c;帮助投资者及时把握盘中主要资金流&#xff0c;做出更准确的投资决策。简而言之&#xff0c;Level-2最大的作用就是提前看到主力的大单&#xff0c;对于追逐日线跌停…

js解析jwt中的数据,将base64转为json方式,以及需要注意的地方

jwt前端解析 ​当我们做前后端分离项目时&#xff0c;需要将jwt保存在前端&#xff0c;有时候需要将jwt中的数据解析出来&#xff0c;网上有很多用第三方组件的方式&#xff0c;但是js的原生方法就也可以解决&#xff0c;虽然存在兼容等问题&#xff0c;但是修改一下也是可用的…

“新白色战场”增长公式发布丨数说故事2023低温鲜奶洞察

重点内容抢先看 低温鲜奶成为乳制品品类新的增长点&#xff0c;头部品牌纷纷入局&#xff0c;“新白色战场”厮杀逐年激烈。 数说故事发布《2023低温鲜奶品类洞察报告》&#xff0c;根据近两年社媒电商数据深度分析&#xff0c;总结出低温鲜奶品类增长公式。 产品力 口感性价…

ElasticSearch 同步MySQL数据方案汇总

叙述 在实际项目开发中&#xff0c;我们经常将Mysql作为业务数据库&#xff0c;ES作为查询数据库&#xff0c;用来实现读写分离&#xff0c;缓解Mysql数据库的查询压力&#xff0c;应对海量数据的复杂查询。这其中有一个很重要的问题&#xff0c;就是如何实现Mysql数据库和ES的…

Matlab如何隐藏坐标轴框线,但保留刻度及刻度标签

假如我们用Matlab绘制了这样一幅堆叠图&#xff1a; 看起来&#xff0c;哪哪都好&#xff0c;但就是感觉两条黑色的坐标轴框线有些碍事。 于是想&#xff0c;该怎么去掉呢&#xff1f; 网上对于这一问题比较常见的解答是&#xff0c;将坐标轴颜色设置为背景颜色&#xff1a; …

2023,没有人不想做黄牛

【潮汐商业评论/原创】 “没办法啊&#xff0c;只能退票了。”作为奶茶十几年的老粉&#xff0c;好不容易从其他粉丝手里买到票的Sarah无奈道。 “刘若英&#xff0c;12小时内退票”、“梁静茹&#xff0c;24小时内退票”…… 近日“演唱会闹退票”登上了热搜。起因是5月7日&…

nuitka打包python的PyQt5成exe可执行文件

使用nuitka打包python的PyQt5 可以打包多文件,也可以打包单文件。 使用的python版本是3.8.10 1、下载gcc 方式1:可以到网站下载,点我跳转 方式2:可以直接去网盘下载,点我跳转 提取码:8888 网盘里面也有python3.8.10的安装包,下载后直接安装即可。 下载64位 win…

CoolShell 博客备份QA问答

芝兰生于深谷&#xff0c;不以无人而不芳; 君子修身养德&#xff0c;不以穷困而改志 这是左耳朵耗子-陈皓[1]的座右铭&#xff0c;他的中文技术博客酷壳 - CoolShell[2]可能是许多技术人员的圣地&#xff0c;至少对我来说是的。 coolshell_talk 他在极客时间的专栏&#xff0c;…

深度学习--主动学习

主动学习简介 主动学习是指对需要标记的数据进行优先排序的过程&#xff0c;这样可以确定哪些数据对训练监督模型产生最大的影响。主动学习是一种学习算法可以交互式查询用户(teacher 或 oracle)&#xff0c;用真实标签标注新数据点的策略。主动学习的过程也被称为优化实验设计…

Oracle 存储过程语法

Oracle 存储过程语法 1. 创建表&#xff08;测试数据准备&#xff09; -- 创建用户表 create table TT_USER (USERID NUMBER(10),USERNAME VARCHAR2(255),PASSWORD VARCHAR2(255),SEX VARCHAR2(1) );INSERT INTO TT_USER VALUES (101, zhang, 111, 1); INSERT INTO TT…

Win11校园网不弹出登录页面怎么回事?

Win11校园网不弹出登录页面怎么回事&#xff1f;最近有用户在使用校园网的时候遇到了一些问题&#xff0c;访问登录网站的时候&#xff0c;一直无法显示登录的界面。那么遇到这个情况如何去进行解决呢&#xff1f;一起来看看以下的解决方法分享吧。 解决方法如下&#xff1a; 方…

【零基础学机器学习 2】 机器学习的实操步骤-以及在Python中实现机器学习模型

文章目录 1. 收集数据2. 准备数据3. 选择模型4. 训练模型5. 评估模型6. 参数调整7. 进行预测在Python中实现机器学习模型 机器学习是一种人工智能的分支&#xff0c;它使用算法和统计模型来让计算机系统自动地从数据中学习&#xff0c;并根据学习结果做出预测或决策。机器学习的…

智能双向嵌入式UART转CAN模块 串口 RS232 RS485 UART CAN转换器

CANUART-100TL系列智能双向UART转CAN模块具有一路TTL UART串口通道和一路CAN通道&#xff0c;实现CAN与串口 UART之间的双向数据智能转换。超小型灌封模块设计&#xff0c;方便用户集成到电路板上&#xff0c;快速通过MCU的UART口扩展CAN通道。 智能双向UART转CAN模块提供“…

Docker高级:Compose 容器编排

目录 一、Docker Compose 概述二、使用 Docker Compose三、常用命令四、编排微服务Ⅰ、搭建微服务Ⅱ、编写Dockerfile构建镜像Ⅲ、启动容器&#xff0c;测试服务Ⅳ、使用Compose编排容器 五、总结 一、Docker Compose 概述 Compose 是Docker公司推出的一个软件&#xff0c;可以…

跟着我学 AI丨AIGC,自媒体的核武器

自从 ChatGPT 火爆全网之后&#xff0c;AI 相关概念的热度就一直持续高涨不下&#xff0c;尤其是大众都在关注的 AI 的应用场景方向&#xff0c;更是疯狂。无论是 AI 圈内人还是以前对 AI 完全没有认知的人&#xff0c;都想借助 AI 挣上一笔。目前来说最受关注的 AI 应用场景&a…

阿里云数据库ClickHouse产品和技术解读

摘要&#xff1a;社区ClickHouse的单机引擎性能十分惊艳&#xff0c;但是部署运维ClickHouse集群&#xff0c;以及troubleshoot都不是很好上手。本次分享阿里云数据库ClickHouse产品能力和特性&#xff0c;包含同步MySQL库、ODPS库、本地盘及多盘性价比实例以及自建集群上云的迁…