利用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的配置 ... 
随机推荐
- 那些有实力进入 BAT 的本科生,都做对了什么事?
			作者:黄小斜 文章来源:微信公众号[黄小斜] 最近这段时间,我们部门来了几个年纪轻轻的本科生,最小的比我们小五岁左,这对于我来说还是比较有冲击力的. 想想我也是九0出头的老腊肉了,想当年我上大学的时候 ... 
- c++2的幂次方
			c++2的幂次方 题目描述 任何一个正整数都可以用2的幂次方表示. 同时约定用括号来表示方次,即a的b次,可以表示为a(b). 由此可知,137可以表示为: 2(7)+2(3)+2(0) 进一步: ... 
- 阿里云体验:安装jdk
			在阿里云的linux服务器上默认是没有安装java环境的,需要自己安装.查了许多资料,发现这篇文章简洁易用.http://www.cnblogs.com/cloudwind/archive/2012/ ... 
- 生产Server遭挖矿程序入侵,暴力占用CPU
			区块链的火热,利益驱使必然导致不少PC或Server,被变成肉鸡,执行挖矿程序进行挖矿,进而导致我们正常的程序无法正常. (Centos7 Server)使用top命令查看服务器进程运行情况,发现几个 ... 
- 把 python 程序打包成 egg 或者 whl 安装包
			原文出处:http://www.worldhello.net/2010/12/08/2178.html 本文略有改动 1.1 安装setuptools 首先要安装setuptools工具.Debian ... 
- Netty-Channel架构体系源码解读
			全文围绕下图,Netty-Channel的简化版架构体系图展开,从顶层Channel接口开始入手,往下递进,闲言少叙,直接开撸 概述: 从图中可以看到,从顶级接口Channel开始,在接口中定义了一套 ... 
- 1.Actor编写-ESGrain与ESRepGrain
			ESGrain 生命周期 Ray中ESGrain继承自Grain扩展了Grain的生命周期.Grain的生命周期参见文档附录:1-Grain生命周期-译注.md ESGrain重写了Grain的OnA ... 
- Java监控任务的生命周期
			Observable: public interface Observable { enum Cycle{ STARTED, RUNNING, DONE, ERROR } Cycle getCycle ... 
- SpringBoot学习笔记3
			十六:自定义拦截器 参考文档 16.1 编写拦截器类 extends WebMvcConfigurerAdapter 并重写WebMvcConfigurerAdapter,如下: package co ... 
- Shiro在Web环境下集成Spring的大致工作流程
			1,Shiro提供了对Web环境的支持,其通过一个 ShiroFilter 入口来拦截需要安全控制的URL,然后进行相应的控制. ①配置的 ShiroFilter 实现类为:org.spri ... 
