资讯专栏INFORMATION COLUMN

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

scola666 / 1321人阅读

摘要:只有在用户点击前进回退按钮,或,,服务器端结合前端,可以用以下方式处理此处的为单页面容器,即放置本文中的所有代码文件欢迎交流

[toc]

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

在线演示codepen

html代码
 
hash 路由
hash 1 hash 2 hash 3 other
history 路由
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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99680.html

相关文章

  • 自己动手实现一个前端路由

    摘要:单页面应用利用了动态变换网页内容避免了页面重载路由则提供了浏览器地址变化网页内容也跟随变化两者结合起来则为我们提供了体验良好的单页面应用前端路由实现方式路由需要实现三个功能浏览器地址变化切换页面点击浏览器后退前进按钮,网页内容跟随变化刷新浏 单页面应用利用了JavaScript动态变换网页内容,避免了页面重载;路由则提供了浏览器地址变化,网页内容也跟随变化,两者结合起来则为我们提供了体...

    psychola 评论0 收藏0
  • vue-router实现原理

    摘要:我们知道是的核心插件,而当前项目一般都是单页面应用,也就是说是应用在单页面应用中的。原理是传统的页面应用,是用一些超链接来实现页面切换和跳转的其实刚才单页面应用跳转原理即实现原理实现原理原理核心就是更新视图但不重新请求页面。 近期面试,遇到关于vue-router实现原理的问题,在查阅了相关资料后,根据自己理解,来记录下。我们知道vue-router是vue的核心插件,而当前vue项目...

    vibiu 评论0 收藏0
  • 彻底理清前端页面应用(SPA)的实现原理 【精读源码】

    showImg(https://segmentfault.com/img/bVbvOmp?w=1612&h=888); 随着React Vue前端框架的兴起,出现了Vue-router,react-router-dom等前端路由管理库,利用他们构建出来的单页面应用,也是越来越接近原生的体验,再也不是以前的点击标签跳转页面,刷新整个页面了,那么他们的原理是什么呢? 优质gitHub开源练手项目: ...

    xiaodao 评论0 收藏0
  • 彻底理清前端页面应用(SPA)的实现原理 【精读源码】

    showImg(https://segmentfault.com/img/bVbvOmp?w=1612&h=888); 随着React Vue前端框架的兴起,出现了Vue-router,react-router-dom等前端路由管理库,利用他们构建出来的单页面应用,也是越来越接近原生的体验,再也不是以前的点击标签跳转页面,刷新整个页面了,那么他们的原理是什么呢? 优质gitHub开源练手项目: ...

    崔晓明 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<