前言
在前端架构中,路由的设计的合理与否决定了这个项目的是否优秀。现在前端的框架angular,vue react都有对应的路由插件,在页面渲染方便基本都不用我们前端工程师考虑,基本上我们安装他们的文档配置好路由都能良好的运行,但是这并不意味我们不需要去掌握路由的实现原理。
发展
初始的web路由(后端控制)
- 后台控制路由渲染
- 页面跳转会重新渲染整个页面
- 浏览可以自动记录页面路由跳转历史
- 所有内容需要浏览器向服务器发出请求
- 服务器端返回对应路由的信息
- 需要浏览器再次解析返回信息
var express = require('express'); var path = require('path'); var app = express(); // 设置模版渲染引擎路径 app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); //nodejs根据路由渲染 var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/index', function(req, res, next) { res.render('index', { title: 'I am index.' }); }); /* GET home page. */ router.get('/admin', function(req, res, next) { res.render('admin', { title: 'I am admin.' }); }); module.exports = router;
总结:简单来说路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。
单页面路由机制(前端完全控制)
- 静态文件只需要请求一次
- 路由跳转页面只需要部分刷新
- 前端完全设计路由
- 只有动态数据与后台进行ajax交互
- 实现方式:hash和history
对比
后台控制 | 单页面路由机制 | |
加载速度 | 加载所有数据,重新渲染dom | 部分dom渲染以及部分数据 |
切换效果 | 重新刷新中间白屏 | 平滑过渡 |
动态数据交互 | ajax交互 | ajax交互 |
维护成本 | 前后端沟通 | 只需要前端控制 |
从对比中我们可以发现,单页面路由机制无论在维护成本,渲染速度以及用户体验度上都是完胜后台控制设计的路由。这也是目前除了一些老项目还采用后台控制路由的方式其他基本都是采用单页面路由机制渲染的原因。
注:现在的ssr渲染本质上也是属于单页面路由设计,ssr只是采用了后台进行首屏渲染,路由的实际控制权还是在前端的。
单页面路由实现方式
hash实现方式
- 介绍:还记得刚开始工作时做过公司的官网,那个时候tab的跳转就是直接加载另一个html,但这样会在第一次切换是如果页面资源过大会导致白屏。后来搜索了下解决方案就是所有的tab内容放到一个页面里每个部分加上不同的hash然后点击tab通过hash来显示相应的html。我想这应该是最初的单页面路由实现方式的。
- 实现方式:利用dom的事件hashchange(当URL的片段标识符更改时,将触发hashchange事件 (跟在#符号后面的URL部分,包括#符号))来监听路由上hash的边从而渲染对应的页面。
// 监听hash变化 window.addEventListener('hashchange', function(event){ console.log('===current hash===') console.log(window.location.hash) console.log('new url====='+ event.newURL); // hash 改变后的新 url console.log('old url====='+ event.oldURL)// hash 改变前的旧 url },false) //或者此种写法 window.onhashchange = funcRef; function funcRef(event){ ...... } let hash = window.location.hash; // 获取当前 hash 值 //在html中可以加入一下代码测试 <div> <a href="#/hash1">hash1</a> <a href="#/hash2">hash2</a> <a href="#/hash3">hash3</a> </div>
注:回调函数中的参数说明请查看文档
- 总结:hash路由可以较好的实现页面的交互,并且对于浏览器有良好的兼容性,但是唯一不足的是他的设计美观上,hash路由中必须带个#,这对于我们线上项目来说是非常不美观的,随着html5的api发展hash在前端路由中必将会被慢慢的取代。
h5的history实现
- 介绍:在 HTML5 出现之前,浏览器就已经有了 history 对象。但在早期的 history 中只能用于多页面的跳转有以下的api:
history.go(num);// num 正数为前进num页 负数为后退num页 history.forward();// 前进一页 history.back(); //后退一页
在html5的api中history新增了可以控制路由的几个api:
//param1:状态对象 title:标题(保留字段) url:路由url history.pushState(stateObj,title,url) history.replaceState(stateObj,title,url) // 替换当前路由状态 history.state // 获取history中的状态对象
注:详细文档请查看mdn文档
- 实现方式:
待研究过react-router和vue-route源码后再来补上
对比
hash模式的优点:
- 兼容性更好
- 无需服务器处理非单页应用中的路由
- 当前页面刷新不会404(history需要服务器配置)
history 模式的优点:
- 路由设计更优雅(没有#)。
- 页面中可以继续使用锚点功能
- 相同的路由仍然可以放到历史栈中。
注:就个人而言觉得history是前端路由的发展方向
参考
「前端进阶」彻底弄懂前端路由
总结
自工作以来已有四年多了,接触前端这块应该有五年多了,随着学的东西越多约会发现自己对于知识的匮乏,时而焦虑自己笨拙,时而害怕会被时代抛弃,但随着年龄渐渐的增长,生活渐渐的稳定,心态也慢慢平缓,只要你够努力生活必然不会负你。废话不多说了,最后送诸君一句:书山有路勤为径,学海无涯苦作舟。诸君共勉。