千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆
当前位置:重庆千锋IT培训  >  技术干货  >  JavaScript全解析——前端路由+原生JS实现SPA

JavaScript全解析——前端路由+原生JS实现SPA

来源:千锋教育
发布人:lxl
时间: 2023-05-15 14:38:06

前端路由+原生JS实现SPA

  ●前端路由

  ●路由: 就是一一对应关系的集合

  ●前端路由: 就是一个 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());
}


 

声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。

猜你喜欢LIKE

如何进行mysql数据备份?

2023-05-30

从零开始学Java之Java中的内部类是怎么回事?

2023-05-29

什么是事件流以及事件流的传播机制 ?

2023-05-29

最新文章NEW

什么是servlet的生命周期?servlet请求处理流程是怎样的?

2023-05-30

在java中,super关键字怎样使用

2023-05-29

什么是JavaScript伪数组?

2023-05-25

相关推荐HOT

更多>>

快速通道 更多>>

最新开班信息 更多>>

网友热搜 更多>>