利用hash或history实现单页面路由
在chrome(版本 70.0.3538.110)测试正常
编写涉及:css, html,js, node(koa)
html代码
<div class="hash">
<div class="title">hash 路由</div>
<a href="#/one">hash 1</a> <a href="#/two">hash 2</a> <a href="#/three">hash 3</a> <a onclick="hashRoute.skip('other')">other</a>
<div id="hashContent"></div>
</div>
<div class="history">
<div class="title">history 路由</div>
<div>
<button onclick="historyRoute.skip('pushStateOne')">history.pushState(1)</button>
<button onclick="historyRoute.skip('pushStateTwo')">history.pushState(2)</button>
<button onclick="historyRoute.skip('pushStateThree')">history.pushState(3)</button>
<button onclick="historyRoute.skip('pushStateTwo')">history.replaceState(pushStateTwo)</button>
<button onclick="historyRoute.skip('go')">history.go(2)</button>
<button onclick="historyRoute.skip('forward')">history.forward()</button>
<button onclick="historyRoute.skip('back')">history.back()</button>
</div>
<div id="historyContent"></div>
</div>
css代码
.hash a {
display: inline-block;
padding: 5px 8px;
margin: 10px 10px 10px 0;
font-size: 15px;
text-decoration: none;
border: 0;
cursor: pointer;
color: #fff;
background-color: rgb(17, 130, 236);
}
.title{
margin: 10px 0;
padding: 5px 8px;
border-left: rgb(168, 168, 168) solid 2px;
background-color: rgb(230, 230, 230);
}
.hash div:last-child{
padding: 6px;
min-height: 100px;
background-color: rgb(243, 243, 243);
}
.history{
margin: 10px 0;
}
.history button {
padding: 8px 10px;
border: 0;
color: #fff;
background-color: rgb(250, 144, 44);
}
.history div:last-child{
margin-top: 10px;
padding: 6px;
min-height: 100px;
background-color: rgb(243, 243, 243);
}
JavaScript代码
hash方式
class HashRoute {
setRoute() {
const commandObj = {
one: 'page one',
two: 'page two',
three: 'page three'
}
const hashRoute = location.hash ? location.hash.slice(2) : 'one'
let re = commandObj[hashRoute]
document.getElementById('hashContent').innerHTML = re ? re : 'page not find'
}
skip(path) {
window.location.hash= `#/${path}`
}
init() {
window.addEventListener('DOMContentLoaded', this.setRoute)
// 1.直接更改浏览器地址,在最后面增加或改变#hash;
// 2.通过改变location.href 或 location.hash的值;
// 3.通过触发点击带锚点的链接;
// 4.浏览器前进后退可能导致hash的变化,前提是两个网页地址中的hash值不同
window.addEventListener('hashchange', this.setRoute)
}
}
const hashRoute = new HashRoute()
hashRoute.init()
history 方式
浏览器端代码
// 服务端有效
class HistoryRoute {
constructor() {
this.currentPath = ''
}
renderView(component) {
const route = {
pushStateOne: 'route pushState one',
pushStateTwo: 'route pushState two',
pushStateThree: 'route pushState three',
replaceState: 'route replaceState',
go: 'route go',
forward: 'route forward',
back: 'route back',
notFind: 'not find',
}
document.getElementById('historyContent').innerHTML = route[component]
}
// 这里所有涉及的跳转都用js方式,不采用a标签(采用a标签请设置拦截)
skip(path) {
const commandObj = {
pushStateOne: () => {
history.pushState({ path }, path,path)
this.renderView(path)
},
pushStateTwo: () => {
history.pushState({ path }, path, path)
this.renderView(path)
},
pushStateThree: () => {
history.pushState({ path }, path, path)
this.renderView(path)
},
replaceState: () => {
// 是用来修改当前的history实体而不是创建一个新的,比如连转顺序为1,2,3,1执行replaceState(2),再执行back(),返回1,而不是3
history.replaceState({ path }, path, path)
this.renderView(path)
},
go: () => {
history.go(2)
this.renderView('go')
},
forward: () => {
history.forward()
this.renderView('forward')
},
back: () => {
history.back()
},
}
this.currentPath = path;
commandObj[path]()
}
init() {
window.addEventListener('DOMContentLoaded', () => {
// 针对F5刷新问题:
// 1.可以使用?后面跟参数形式
// 2.统一入口利用忽略地址方式(后端配置 /page/:path 忽略page后跟的所有地址,通过前端去请求page后的对应路由数据,如下)
const path = location.href.split('/page/')
this.skip(path[1])
})
// 调用history.pushState()或history.replaceState()不会触发popstate。
// 只有在用户点击前进回退按钮,(或history.back(),forward,go)
window.addEventListener('popstate', (event) => {
console.log('popstate', this.currentPath, event.state);
const { state } = event
if (state && state.path) {
this.renderView(state.path)
} else {
this.renderView('404')
}
})
}
}
const historyRoute = new HistoryRoute()
historyRoute.init();
服务器端
// 结合前端,可以用以下方式处理
router.get('/page/:path', (ctx, next) => {
ctx.response.type = 'html';
// 此处的singlePageRoute.html为单页面html容器,即放置本文中的所有代码文件
ctx.response.body = fs.createReadStream('./dist/public/files/singlePageRoute.html');
return next();
})
若有疑问或错误,请留言,谢谢!Github blog issues
利用hash或history实现单页面路由的更多相关文章
- 详解单页面路由的几种实现原理(附demo)
前言 路由是每个单页面网站必须要有的,所以,理解一下原理,我觉得还是比较重要的. 本篇,基本不会贴代码,只讲原理,代码在页底会有githup地址,主意,一定要放在服务本地服务器里跑(因为有ajax), ...
- 移动H5页面微信支付踩坑之旅(微信支付、单页面路由模拟、按钮加锁、轮询等常见功能)
开发背景: .net混合开发的vue模板语法的单页面应用,所以不存在脚手架以及没有路由可以跳转. 项目描述: 需要写两个页面,在订单详情页需要点击“请输入手机号”进入手机号绑定页面,手机号绑定成功后自 ...
- AngularJS单页面路由配置恩,理解了就很简单啦
利用route实现单页面跳转功能 利用angularJS开发流程 1)配置好angularJS开发环境 2)利用 yo angular projectname创建项目目录 3)删除掉系统自动生成的一些 ...
- 简单单页面路由跳转demo
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- webpack解决单页面路由问题
index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- angular ,require.js, angular-async-loader实现单页面路由,控制器js文件分离
https://github.com/heboliufengjie/appRoute/tree/re re 分支,实现,路由配置,控制器js文件分离
- hash和history路由的区别
在了解路由模式前,我们先看下 什么是单页面应用,vue-router 的实现原理是怎样的,这样更容易理解路由. SPA与前端路由 SPA(单页面应用,全程为:Single-page Web appl ...
- 浅谈HTML5单页面架构(二)——backbone + requirejs + zepto + underscore
本文转载自:http://www.cnblogs.com/kenkofox/p/4648472.html 上一篇<浅谈HTML5单页面架构(一)--requirejs + angular + a ...
- H5单页面架构:backbone + requirejs + zepto + underscore
首先,来看看整个项目结构. 跟上一篇angular类似,libs里多了underscore和zepto.三个根目录文件: index.html:唯一的html main.js:requirejs的配置 ...
随机推荐
- SPOJ STC02 - Antisymmetry(Manacher算法求回文串数)
http://www.spoj.com/problems/STC02/en/ 题意:给出一个长度为n的字符串,问其中有多少个子串s可以使得s = s按位取反+翻转. 例如样例:11001011. 10 ...
- HDU 3416:Marriage Match IV(最短路+最大流)
http://acm.hdu.edu.cn/showproblem.php?pid=3416 题意:给出n个点m条边,边信息分别是两个端点和一个费用,再给出一个起点和一个终点,问从起点到终点的完全不相 ...
- 使用wincc C脚本查找窗口句柄的方法
关于窗口句柄的用法,网上可以搜到很多相关的文章,本文以windows API接口函数为例,简单介绍一下基本使用,主要包括找到此窗体,在找到的窗体写入数据,对窗体进行关闭,最大化,最小化的操作: 1.利 ...
- Contiki源码分析--CPU为cc253x里的uart0.c
我所使用的Contiki系统是contiki-sensinode.理解该文需要有cc2530里uart的相关知识,具体寄存器的用法不做介绍. 先放上所有代码,然后再仔细分析. #include < ...
- 【题解】【A % B Problem(P1865)】-C++
题目背景 题目名称是吸引你点进来的 实际上该题还是很水的 题目描述 区间质数个数 输入输出格式 输入格式: 一行两个整数 询问次数n,范围m 接下来n行,每行两个整数 l,r 表示区间 输出格式: 对 ...
- 利用百度AI OCR图片识别,Java实现PDF中的图片转换成文字
序言:我们在读一些PDF版书籍的时候,如果PDF中不是图片,做起读书笔记的还好:如果PDF中的是图片的话,根本无法编辑,做起笔记来,还是很痛苦的.我是遇到过了.我们搞技术的,当然得自己学着解决现在的痛 ...
- [leetcode] 392. Is Subsequence (Medium)
原题 判断子序列 /** * @param {string} s * @param {string} t * @return {boolean} */ var isSubsequence = func ...
- 一文带你实现RPC框架
想要获取更多文章可以访问我的博客 - 代码无止境. 现在大部分的互联网公司都会采用微服务架构,但具体实现微服务架构的方式有所不同,主流上分为两种,一种是基于Http协议的远程调用,另外一种是基于RPC ...
- SQL SERVER Suspect(质疑/挂起) 状态恢复
数据库服务器,在断电时,偶尔会出现Suspect状态,导致数据库无法使用. 解决办法如下: 数据库名带‘[]’可以避免库名中带‘.’等特殊符号的情况. USE [master]GOALTER DATA ...
- C#编程.函数.委托
注:委托最重要的用途最讲到事件和事件处理时才能说清,这里先简单介绍一下关于委托的一些内容 委托是一种可以把引用存储为函数的类型.这听起来相当棘手,但其机制是非常简单的. 1)委托的声明非常类似与函数, ...