博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
原生实现前端路由
阅读量:4085 次
发布时间:2019-05-25

本文共 3275 字,大约阅读时间需要 10 分钟。

在 Web SPA 中,前端路由描述的 URL 与 UI 之间的单向映射关系,即 URL 变化引起 UI 页面的更新(无需刷新页面)。

核心问题

上面我们提到,在前端路由中,当 URL 发生变化时,我们需要在不刷新页面的情况下,触发 UI 页面的更新。因此,在实现前端路由时,我们需要解决以下两个核心的问题。

  • 如何检测 URL 是否变化?
  • 如何改变 URL 却不引起页面刷新?

我们可以从 Hash 和 History 两种实现方式回答上述两个问题。

  • 在 Hash 方式中,我们可以通过 hashchange 事件监听 URL 的变化,以下场景会触发 hashchange 事件:通过浏览器前进后退改变 URL 、通过标签改变 URL 、通过 window.location 改变 URL 。Hash 是 URL 中 # 及后面的部分,改变 URL 中的 Hash 部分不会引起页面刷新。
  • 在 History 方式中,我们可以通过 popstate 事件监听 URL 的变化。我们可通过调用 pushStatereplaceState 两种方法,改变 URL 而不引起页面刷新。值得注意的是,通过浏览器前进后退改变 URL 时会触发 popstate 事件,而通过 pushStatereplaceState 或标签改变 URL 并不会触发 popstate 事件,因此我们需要手动拦截。

实现

代码地址:

为便于测试,我们使用了 作为页面服务器,相关命令如下。

# 安装依赖。yarn# 对 Vanilla Hash 进行演示。yarn vanilla.hash# 对 Vanilla History 进行演示。yarn vanilla.history复制代码

Vanilla

现在,我们使用原生 HTML/JS 实现 Hash 和 History 两种模式的前端路由,不依赖任何框架。

Hash

页面 vanilla.hash.html 的具体代码如下。

      
Hash Route - Vanilla
复制代码

vanilla.hash.js 中,我们通过对 hashchange 事件进行监听,从而检测 URL 是否变化。当 URL 变化时,我们调用 onHashChange 函数,通过修改元素的 innerHTML 属性,在页面无刷新的情况下,实现页面视图的更新。

// 维护 UI 页面。let routerView = null;// 路由变化时,根据路由渲染对应 UI 页面。function onHashChange() {  switch (window.location.hash) {    case '':    case '#/home':      routerView.innerHTML = 'Home';      return;    case '#/about':      routerView.innerHTML = 'About';      break;    default:  }}// 页面加载完不会触发 hashchange,这里主动触发一次 hashchange 事件。window.addEventListener('DOMContentLoaded', () => {  routerView = document.querySelector('#routeView');  onHashChange();});// 监听路由变化。window.addEventListener('hashchange', onHashChange)复制代码

History

页面 vanilla.history.html 的具体代码如下。

      
History Route - Vanilla
复制代码

vanilla.history.js 中,我们通过对 popstate 事件进行监听,从而检测 URL 是否变化。当 URL 变化时,我们调用 onPopState 函数,通过修改元素的 innerHTML 属性,在页面无刷新的情况下,实现页面视图的更新。

由于通过 pushStatereplaceState 和标签改变 URL 时,并不会触发 popstate 事件,我们需要手动拦截。

// 维护 UI 页面。let routerView = null;// 路由变化时,根据路由渲染对应 UI 页面。function onPopState() {  switch (window.location.pathname) {    case '/':    case '/home':      routerView.innerHTML = 'Home';      return;    case '/about':      routerView.innerHTML = 'About';      break;    default:  }}// 页面加载完不会触发 hashchange,这里主动触发一次 hashchange 事件。window.addEventListener('DOMContentLoaded', () => {  routerView = document.querySelector('#routeView');  // 刷新页面。  onPopState();  // 拦截  标签点击事件默认行为, 点击时使用 pushState 修改 URL并更新手动 UI,从而实现点击链接更新 URL 和 UI 的效果。  const links = document.querySelectorAll('a[href]');  links.forEach(el =>    el.addEventListener('click', function handler(e) {      e.preventDefault();      // 手动拦截。      window.history.pushState(null, '', el.getAttribute('href'));      onPopState();    }),  );});// 监听路由变化。window.addEventListener('popstate', onPopState);复制代码

在使用 History 模式时,当我们刷新页面,会出现 404 页面。为解决这个问题,我们需要 rewrite 请求。

在 Nginx 中,我们需要添加以下设置:对于所有的请求,我们都响应相同的页面,让页面来接管路由。

location / {  try_files $uri $uri/ /vanilla.history.html;}复制代码

serve 中,我们只需定义 rewrites 数组即可。

{  "rewrites": [    {      "source": "**",      "destination": "vanilla.history.html"    }  ]}复制代码

参考资料

作者:Jiahonzheng
链接:https://juejin.im/post/5e395994f265da573e6713eb
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的文章
JVM内存模型_Minor GC笔记
查看>>
SpringCloud学习之PassCloud——(一)PassCloud源代码下载
查看>>
Linux下安装Python环境并部署NLP项目
查看>>
Nginx篇-springCloud配置Gateway+Nginx进行反向代理和负载均衡
查看>>
Nginx篇-Nginx配置动静分离
查看>>
缓存篇-Redis缓存失效以及解决方案
查看>>
缓存篇-使用Redis进行分布式锁应用
查看>>
缓存篇-Redisson的使用
查看>>
phpquery抓取网站内容简单介绍
查看>>
找工作准备的方向(4月22日写的)
查看>>
关于fwrite写入文件后打开查看是乱码的问题
查看>>
用结构体指针前必须要用malloc,不然会出现段错误
查看>>
Linux系统中的美
查看>>
一些实战项目(linux应用层编程,多线程编程,网络编程)
查看>>
我觉得专注于去学东西就好了,与世无争。
查看>>
原来k8s docker是用go语言写的,和现在所讲的go是一个东西!
查看>>
STM32CubeMX 真的不要太好用
查看>>
STM32CubeMX介绍、下载与安装
查看>>
不要买铝合金机架的无人机,不耐摔,易变形弯曲。
查看>>
ACfly也是基于FreeRTOS的
查看>>