资讯专栏INFORMATION COLUMN

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

longshengwang / 1508人阅读

摘要:监听的变动省略其他代码省略其他代码这样,我们就初步实现了一个路由,那么接下来,我们来看看路由怎么实现。

前言

用过现代前端框架的同学,对前端路由一定不陌生, vue, react, angular 都有自己的 router, 那么你对 router 的工作原理了解吗?
如果还不了解, 那么请跟我一起来手写一个简单的前端路由, 顺便了解一下.

实现路由的2种方式

hash模式

history模式

缺点:

hash:丑(地址栏要多一个#), 某些特殊场景有坑 ,如微信支付回调

history: 兼容性较差, 直接访问会400 ,除非后端或者服务器有做处理

基本原理

hash是基于 监听 hashchange 事件实现的,history 是基于 pushState 和 popState,

实现

由于history兼容性较差,而且实现方式基本没多大区别,本文就以hash模式来实现,history的实现方式只实现不同的部分。



    
    Document





以上就是hash模式的最简单实现,查看控制台,可以看到不管是点击跳转按钮,还是点击浏览器的前进/后退按钮,控制台都会输出当前页面对应的 "url",有了 "url",我们就可以对内容做条件渲染了

我们在上面的代码的基础上,稍作修改一下,增加2个div,一个是login,一个是index



    
    Document
    




这样,我们就能根据不同的hash地址,显示不同的内容,是不是已经有点路由的味道了呢?但是目前还无法传參,传參的方式有很多种,最常见最通俗的,应该是query string 了吧? query string 其实很简单,解析url即可。

    // 监听hash的变动
    window.addEventListener("hashchange", function (e) {
        let url = location.hash.slice(1) || "index"
        // 解析url
        let questionIndex = url.indexOf("?")
        let path, query
        if(questionIndex >= 0){
            path = url.substr(0,questionIndex)
            let queryString = url.substr(questionIndex+1)
            let queryArray = queryString.split("&")
            let queryObject = {}
            queryArray.map(str => {
                let equalIndex = str.indexOf("=")
                if(equalIndex > 0) {
                    let key = str.substr(0,equalIndex)
                    let value = str.substr(equalIndex+1)
                    queryObject[key] = value
                }
            })
            query = queryObject
        } else {
            path = url
            query = {}
        }
        
        console.log("接收到的参数", query)
        setVisible(path)
    })

这样,我们就能获取到URL上传递的query string , 还顺便解决了传參会导致路由解析不正确的bug.

传參其实还有个更简单的方法,就是 设置一个全局变量 param,然后在需要传值的时候,直接对param 赋值即可

    // 设置一个全局变量
    var param = {}
    // 页面跳转
    // 这个多了个参数 args
    function hashPush(url, args) {
        location.hash = "#" + url
        param = args
    }

由于是全局变量,所以可以在任意位置使用 param,不过这样直接使用全局变量的方式,也有它的弱点,就是点击返回按钮的时候无法保存变量,而query string 因为是在 url 里面的,所以返回的时候,可以拿到上个页面的 query string,
那我们有没有办法让全局变量的方式也能保存上一个页面的参数呢? 我们来稍微修改一下代码

    // 设置一个全局变量
    var param = {}
    // 页面跳转
    // 这个多了个参数 args
    function hashPush(url, args) {
        location.hash = "#" + url
        // 如果有传args参数,就在 param 对象下建一个名字跟当前url一样的对象,并把args赋值给它
        if(args) {
            param[url] = args
        }
    }

那我们在 hashchange 的时候,可以根据url来定位该页面的参数。

    // 监听hash的变动
    window.addEventListener("hashchange", function (e) {
        // 省略其他代码
        args = param[path] || {}
        // 省略其他代码
    })

这样,我们就初步实现了一个hash路由,那么接下来,我们来看看history路由怎么实现。

history 模式

history 模式主要依靠 调用 history.pushState() 方法 和 监听 popstate 事件。

history.pushState() 方法接收3个参数:

要传递的数据(参数)

给页面设置的标题(兼容性差,几乎没用)

url

我们看看调用实例

    history.pushState({id:1}, "我是页面标题", url)

需要注意的是 pushState 的时候,并不会触发 popstate 事件,只有在前进后退的时候,才会触发,所以 pushState 之后,需要手动去设置页面的相关状态。如上面的例子,我们需要这样做

    history.pushState({id:1}, "我是页面标题", url)
    setVisible(url)

然后监听 popstate 事件,捕获 前进/后退

 window.addEventListener("popstate",function (e) {
     // e.state 就是你 pushState 的时候,传的第一个参数
     let state = e.state || {}  
     let url = state.target.location.pathName
     //  根据参数 做一些其他操作
  })
最后

本文最终实现代码已经放在 github上,想要直接看效果的同学,可以上去直接copy,运行。

如果觉得本文对您有用,请给本文的github加个star,万分感谢

另外,github上还有其他一些关于前端的教程和组件,有兴趣的童鞋可以看看,你们的支持就是我最大的动力。

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

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

相关文章

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

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

    psychola 评论0 收藏0
  • webpack+vue项目实战(三,配置功能操作页和组件的按需加载)

    摘要:但是实际上,回款管理和开票管理的组件文件也是加载了。所以下面引用按需加载来处理。是不是小很多了,然后和是按需加载的,就是需要的时候才加载。 1.前言 上篇文章(webpack+vue项目实战(二,开发管理系统主页面)),实现了,侧边栏的一个操作,点击侧边栏的一些操作,最重要的就是路由的切换。看了上一篇的伙伴也不难发现,除了点击侧边栏‘首页’之外,点击其它的都是白色的一片。原因我想大家都...

    endless_road 评论0 收藏0
  • 记一次vue仿网易云音乐的单页面应用

    摘要:说明一直想做一个基于的项目但是因为项目往往要涉及到后端的知识不会后端真的苦所以就没有一直真正的动手去做一个项目。直到发现上有网易云音乐的才开始动手去做。仅仅完成了首页登入,歌单,歌曲列表页。 说明 一直想做一个基于VUE的项目,但是因为项目往往要涉及到后端的知识(不会后端真的苦),所以就没有一直真正的动手去做一个项目。直到发现GitHub上有网易云音乐的api NeteaseCloud...

    hqman 评论0 收藏0
  • 使用next.js结合GITHUB ISSUE实现博客。

    摘要:而更多的应用采用的是简单的同构实现。请使用动态路由进行处理。后来用布署频繁调试,发现自定义在上并不能用,看建议使用动态路由。如果要取消这种行为可以使用方法。利用动态实现代码块切片。如果使用的话,建议使用动态路由去做布署啦。 使用next.js结合GITHUB ISSUE实现博客。 起因 。。。。起因是因为在某网站看到有一些类似实现。打算自己也做个side-project。 习惯性的对自...

    SillyMonkey 评论0 收藏0
  • JS或Jquery

    摘要:大潮来袭前端开发能做些什么去年谷歌和火狐针对提出了的标准,顾名思义,即的体验方式,我们可以戴着头显享受沉浸式的网页,新的标准让我们可以使用语言来开发。 VR 大潮来袭 --- 前端开发能做些什么 去年谷歌和火狐针对 WebVR 提出了 WebVR API 的标准,顾名思义,WebVR 即 web + VR 的体验方式,我们可以戴着头显享受沉浸式的网页,新的 API 标准让我们可以使用 ...

    CatalpaFlat 评论0 收藏0

发表评论

0条评论

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