扒一扒路由的演变过程

路由

1. 从前的请求 —— 服务端渲染(SSR:Server Side Render)

在最开始,在浏览器中向服务端发送一个请求,服务端会把 html 字符串生成好,再发送给客户端,客户端直接渲染即可。

并不是说一个 html 就只请求了一次服务端。一个 html 里可能会引用一些 js、css 文件,这些静态资源都是放在服务端的。当浏览器渲染服务端返回的 html 字符串,读到诸如
<script src="js/jquery.js"></script> 时会再次向服务端发送一条请求去获取 jquery.js 资源的,获取回来之后在浏览器中加载一遍。

缺点:在后管系统中,当从“用户管理”菜单跳转到“角色管理”菜单时,往往变化的只是表格的字段以及数据,但在服务端渲染中每次都需要全部请求一遍。请求头部横条,请求左侧菜单栏,重新加载 jquery.js 等等。我们希望不需要改变的东东就别动了,修改变局部。

2. Ajax 出现实现局部刷新

ajax 的出现解决了上面每次请求页面都全部刷新的问题,只是请求数据,然后通过 Dom 操作修改 html 中表格相关的东东。

缺点:使用 ajax 异步请求之后,点击浏览器的回退上一个页面会发现没效果,因为这次请求仅仅是数据的请求,并没有重新刷新页面,也就没有加入到浏览器历史栈中。

3. 单页应用(SPA:Single Pagination Application)

单页应用的出现解决了服务端渲染和 ajax 存在的问题。

解决服务端渲染的问题:

人们开始想,从“用户管理”菜单跳转到“角色管理”菜单时,需要请求服务端获取 html 之后在浏览器中渲染。这个渲染的过程包括创建一个个 dom 元素,如 div dom 元素,p dom 元素。他们会认为这一过程很消耗性能,事实也是如此,可以试着在浏览器调试台中输入:document.createElement('div') 会发现仅仅创建一个 div 元素附带创建了很多属性和方法,那些东东你可能压根就用不上。

单页应用的解决方式是,在页面第一次加载的时候就把“用户管理”的表格 dom 元素和“角色管理”的表格 dom 元素都加载进来,当再次从“用户管理”切换到“角色管理”时,只需要渲染
“角色管理” 的表格 dom,而不是像服务端渲染那样将整个页面都渲染一遍,渲染的少了,性能上无疑得到了提升。这一点和 ajax 有点相似。

单页应用与 ajax 的区别:
ajax 是先请求数据,然后在浏览器通过 js 创建 dom 进行替换。单页应用在第一次加载应用的时候将 dom 都加载到浏览器中,只不过先用了“用户管理”表格 dom,“角色管理”表格 dom 也加载进来了,放在那暂时不用。这种通过点击不同菜单,自动替换不同的 dom 的方式就叫做路由。

还有一点区别就是单页应用解决了 ajax 的问题:单页应用通过 hashHistory 和 browerHistory 可以将每次的路由都加入到浏览器的历史栈,这样点击回退按钮就可以回到上一个页面。
说起来 ajax 也可以通过 hashHistory 和 browerHistory 将路由添加到历史栈,只不过历史大环境下决定它还是功能专一点。

当然,单页应用也有个大问题,那就是首次加载时间很长,造成页面出现白屏。单页应用第一次加载时就会取请求服务端获取所有 html 和 js,然后接下来的操作都在浏览器端进行了,
浏览器会去渲染这些文件,但由于东东太多了,在浏览器端会出现短暂白屏的现象。
为什么服务端渲染不会有白屏现象:因为服务端只会返回 html字符串,浏览器只要渲染一下即可,渲染的东西少了,自然就快了。

4. 路由的概念

去银行办理业务,银行小姐姐会询问你办理什么业务,然后教你不同的操作。有一张表:

业务 操作
办理银行卡 先做xx,再做xx
办理网上银行业务 先做yy,再做yy

去上厕所,如果你是女生,就进入女厕所,你是男生,就进入男厕所。有一张表:

性别 厕所
男生 男厕所
女生 女厕所

你去你女朋友宿舍楼下找她,你告诉宿管大妈你女朋友是xx专业xx班的学生,宿管大妈告诉你去几楼几零几。有一张表:

姓名 宿舍
张晓丽 503 宿舍
李美丽 301 宿舍

回到浏览器路由,在浏览器中输入“localost:8000/”会显示首页,输入“localost:8000/user”会显示用户页面,输入“localost:8000/role”会显示角色页面。有一张表:

路由 视图
/ 首页
/user 用户页面
/role 角色页面

在浏览器中路由的作用就是根据你的输入的地址,显示不同的视图。那就意味着首先要定义这样一张路由表。

5. 路由/单页应用的实现原理

了解了路由表,好奇宝宝肯定想知道具体如何实现呢?

单页应用路由的实现分为两个步骤:改变浏览器地址栏地址,视图切换

1)HashHistory 的应用

  • 改变浏览器地址栏地址
    window.location.hash = 'bbbb' 浏览器地址会变成 localhost:8080/#bbbb
    window.location 对象专门处理浏览器地址栏各种操作。
    使用 window.location.hash 操作时,已经将路由 '#bbbb' 添加到了浏览器历史栈中,点击回退按钮可以回退到上一个页面。
  • 添加浏览器事件监听函数
    window.addEventListener('hashchange', function () {})
    此时如果 hash 变化了,就会触发该事件,在这个事件里就可以实现替换局部 dom 的实现了。

2)Browser History (h5 history)的出现
使用 HashHistory 产生的路由 localhost:8080/#bbbb 会有个井号 #,很多人认为这很不美观,但一直也无计可施,直到 h5 的出现,带来了新的 API —— window.history 的更新。

  • 改变浏览器的地址栏地址
    var stateObj = { foo: "bar" };
    history.pushState(stateObj, "page 2", "user");
    可以看到路由变成了 localhost:8000/user,没有了那不美观的 #。关于history api 具体用法,参考:http://blog.csdn.net/tianyitianyi1/article/details/user
  • 添加浏览器事件监听函数
    通过 history api 改变浏览器地址栏地址同样会触发一个事件
    window.onpopstate = function () { }

3)手写 js 实现一个简单的路由功能:

<!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-Compatible" content="ie=edge">
    <title>Hash</title>
</head>
<body>
        <ul class="cs">
            <li class="li">
                <a href="#/" class="button button-primary">首页</a>
            </li>
            <li class="li">
                <a href="#/nav" class="button button-highlight">菜单</a>
            </li>
            <li class="li">
                <a href="#/subpage" class="button button-royal">子页</a>
            </li>
        </ul>
        <div id="app" style="border:2px solid #f00;height:30px;">
                Hello
        </div>
<script>
function Router(){
    //有个名字,用做一件事情
    this.routes = [];
    this.currentUrl = "";
    this.init();//先让他初始化监听事件,然后才调用路由
}

Router.prototype = {
    constructor:Router,
    router:function(path,callback){
        this.routes[path] = callback || function(){};
    },
    refresh:function(){
        this.currentUrl = location.hash.slice(1) || '/';
        this.routes[this.currentUrl]();//通过路由名字去调用相对应的方法
    },
    init:function(){//监听页面:加载的时候、监听改变的时候
        window.addEventListener("load",this.refresh.bind(this),false);
        window.addEventListener("hashchange",this.refresh.bind(this),false);
    }
}

var appObj = document.getElementById("app");
function changeText(text){
    appObj.innerHTML = text;
}

var router = new Router();

router.router("/",function(){
    changeText("首页");
});
router.router("/nav",function(){
    changeText("菜单");
});
router.router("/subpage",function(){
    changeText("子页");
});
</script>
</body>
</html>

6. 最终

目前由于单页应用操作起来更快速,除了首屏加载尴尬的问题,人们提出的方案是使用服务端渲染首屏,之后其它操作都进行单页应用的操作来规避首屏加载的问题。

最终,当硬件与软件发展到一定程度,网速加速到一定程度,单页应用首屏加载虽然需要请求很多东东,但由于网速的变快一瞬间就加载下来,服务端渲染可能就会慢慢退出历史舞台,这也是一种技术的发展趋势。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,725评论 1 92
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,387评论 25 707
  • 啦啦啦啦啦~ 本精酿小白又入了一波小酒∠( ᐛ 」∠)_ 夏天回到家有冰箱 就等于有了酒的圣地ヾ(´∇`)ノ 左一...
    平和岛蹭阅读 509评论 0 3
  • "现在的小孩都毛毛躁躁的吗。呵呵呵……"伴随着一阵爽朗的笑声,从山洞里走出来一位老人,我们都不知所措。这时,雷蒙走...
    古天问阅读 240评论 1 1