博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自己动手实现一个前端路由
阅读量:7251 次
发布时间:2019-06-29

本文共 3377 字,大约阅读时间需要 11 分钟。

前前言

最近工作比较忙,写的比较慢,当我写完这一篇准备发布的时候,发现掘金刚好也有一篇关于前端路由的,而且写的比我详细,不过辛辛苦苦写的总不能删掉吧,再说我的路由风格是纯个人思路实现的,所以还是硬着头皮发了哈。

前言

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

实现路由的2种方式

  1. hash模式
  2. 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个参数:

  1. 要传递的数据(参数)
  2. 给页面设置的标题(兼容性差,几乎没用)
  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     //  根据参数 做一些其他操作  })

最后

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

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

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


其他链接

原文发布时间为:2018年06月29日

本文作者:noahlam

本文来源:
 如需转载请联系原作者
你可能感兴趣的文章
iOS开发之使用Git的基本使用(一)
查看>>
配置云存储网关在线服务支持多个互联VPC-高速通道版
查看>>
6个步骤从头开始编写机器学习算法:感知器案例研究
查看>>
NCalc 学习笔记 (三)
查看>>
NetBeans 成为 Apache 软件基金会顶级项目
查看>>
SSRF在Redis中反弹shell
查看>>
UML关系图
查看>>
SpringBoot 手写切片/面向切面编程
查看>>
动态 Web Server 技术发展历程
查看>>
使用pymysql(使用一)
查看>>
Redisson 3.10.6 发布,Redis 客户端
查看>>
日志框架 - 基于spring-boot - 使用入门
查看>>
用libtommath实现RSA算法
查看>>
基于POLARDB数据库的压测实践
查看>>
通过工具SecureCRTPortable将项目部署到服务器上
查看>>
利用QRCode实现待logo的二维码的创建
查看>>
【云周刊】第190期:阿里云超算揭秘:虚拟机的心脏,物理机的肌肉
查看>>
崩溃bug日志总结3
查看>>
推荐一个有趣的Chrome扩展程序-查看任意网站的开发技术栈
查看>>
shell技巧5 - 全自动打包ipa
查看>>