利用hash或history实现单页面路由

目录

在chrome(版本 70.0.3538.110)测试正常
编写涉及:css, html,js, node(koa)

在线演示codepen

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

原文地址:https://segmentfault.com/a/1190000017240640

原文地址:https://www.cnblogs.com/lovellll/p/10121770.html

时间: 2024-08-26 23:08:37

利用hash或history实现单页面路由的相关文章

详解单页面路由的几种实现原理(附demo)

前言 路由是每个单页面网站必须要有的,所以,理解一下原理,我觉得还是比较重要的. 本篇,基本不会贴代码,只讲原理,代码在页底会有githup地址,主意,一定要放在服务本地服务器里跑(因为有ajax), 希望能帮到你. 众所周知单页面网站的路径跳转全是通过js来控制的,下面咱们来讲讲 第一种:url完全不动型 这一种的情况是url完全不动,即你的页面怎么改变,怎么跳转url都不会改变 这种情况的原理 就是纯ajax拿到页面后替换原页面中的元素, 这种情况没什么好讲的,好的一言不和上代码    de

详解单页面路由的几种实现原理

路由是每个单页面网站必须要有的,本篇基本不会天贴代码,只讲原理,代码在页面底会有github地址,注意,一定要放在本地服务器里跑(因为有AJAX) 众所周知,单页面网站的路径跳转全是通过JS来控制的,下面说说 第一种:URL完全不动型 这一种的情况是URL完全不动,即你的页面怎么改变,怎么跳转URL都不会改变,这种情况的原理就是纯AJAX拿到页面后替换原页面的元素,这种情况没什么好说的,demo在最底下 第二种:带hash(#)型 这种类型的优点就是刷新页面,页面也不会丢 实现原理: 小明说:如

AngularJS单页面路由配置恩,理解了就很简单啦

利用route实现单页面跳转功能 利用angularJS开发流程 1)配置好angularJS开发环境 2)利用 yo angular projectname创建项目目录 3)删除掉系统自动生成的一些自己工程不需要的页面和脚本 4)修改index.html,在 <!-- Add your site or application content here --> 以上注释下面写自己的样式内容,关键是 <div class="container-fluid" id=&qu

webpack解决单页面路由问题

index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatibl

移动前端,单页面路由的一些思考

树状路由结构, 兄弟节点可以互相访问, 子节点回退键回到父节点, 管理一个路由足迹(这个足迹的兄弟节点互相替代),当a,b兄弟节点指向同一个子节点c,c回退,可以回退到正确的父节点. 什么,页面链接没变,不好分享特定页面的地址.你有见过别人发你一个链接,你的APP会自动跳到那个界面? 问题1: 路由状态名字重复? 通过grandfather-father-son这种命名方式.

浅谈HTML5单页面架构(二)——backbone + requirejs + zepto + underscore

本文转载自:http://www.cnblogs.com/kenkofox/p/4648472.html 上一篇<浅谈HTML5单页面架构(一)——requirejs + angular + angular-route>探讨了angular+requirejs的一个简单架构,这一篇继续来看看backbone如何跟requirejs结合. 相同地,项目架构好与坏不是说用了多少牛逼的框架,而是怎么合理利用框架,让项目开发更流畅,代码更容易管理.那么带着这个目的,我们来继续探讨backbone. 首

单页面应用在微信服务号下的登录流程

最近我们的小程序涉及到虚拟支付的问题,在ios端的支付被封掉了??,所以有了在服务号上搞一套H5版的小程序的需求.由于我们小程序是mpvue写的,为了尽量复用之前的样式和逻辑,选择了前后端分离的模式,于是一段新的踩坑之旅开始了.放下wx的jssdk暂且不表,今天来说说登录时遇到的坑. 服务号的登录流程 以前搞过服务号的同学对于它的登录流程应该不陌生,就是当后端检测到当前用户没有授权时,将会重定向到微信的授权页面,当用户点击这个授权的button时,微信会根据Url查询字符串中的重定向URL,重新

关于js单页面实现跳转原理以及利用angularjs框架路由实现单页面跳转

还记得我们刚开始学习html时使用的锚节点实现跳转吗? <a href="#target">我想跳转至目标位置</a> <p>第一条</p> .... <p id="#target">我是目标位置</p> ... 在js中实现跳转也是利用了这一点,下面直接在代码中解释吧: 1 <body> 2 <ul> 3 <li><a href="#/mus

Vue-两种路由模式 hash 和 history

Vue 为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-Router 存在的意义.前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求. hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由. Hash: History: 原文地址:https://www.cnblogs.com/yangchin9/p/10895721.html