前端路由 & 实现原理

前端路由

  • 什么是路由:地址栏的变化、URL到函数的映射

后端路由:又称服务器路由,服务器接收前端发来的http请求后,会根据url找到相应的映射函数,然后执行函数,并将返回值发回给客户端。对于静态资源来说,映射函数就是一个文件读取操作;对于动态资源,映射函数可能是一个数据库读取操作,或者是数据处理操作;根据读取的数据,在服务端使用相应的模板来渲染页面,再返回渲染完毕的页面【⚠️这是早期的做法】

如访问http://xxx/about,服务器收到后,解析出/about,寻找到对应的逻辑,程序吧请求交给对应处理逻辑,完成一次路由分发。

  • 好处:安全性好、SEO好;

  • 缺点:加大服务器压力,不利于用户体验

前端路由:路由的映射函数;当访问不同的路径,会显示不同的页面组件。控制页面跳转

单页应用路由的特点:通过改变url,不会向后端发送新的请求,更新页面视图,所有页面均在客户端渲染

  • 更新地址栏,但是不重新请求页面

  • 两种模式都是使用浏览器接口实现的,除此之外,vue-router还为非浏览器提供了abstract模式,原理为用一个数组stack模拟出浏览器历史记录栈的功能。

缺点:使用前进后退时会重新发请求,没有合理利用缓存。

  • hash:#本身以及后面的字符称为hash,可以通过window.location来获取

    ⚠️a标签和router-link区别,hash模式只关心#后面的路径-

    早期路由实现基于location.hash实现,即#及后面的部分

    • url中的hash只是客户端的一种状态,当向服务器发出请求,hash部分不会被发送;

    • hash值改变,会在浏览器访问历史中增加记录,可以通过浏览器的前进后退控制hash切换

    • 可以通过hashchange事件来监听hash的变化

    • 触发的方式:<a href="#xxx">、location.hash="#xxx"

      http://xxx/about#后面会被服务器忽略,但是JavaScript通过window.location.hash读取到,得到响应逻辑

  • history API

    • history.back()、history.forward()、history.go(xx)

    • html5提供了history API,主要有history.pushState(状态对象,标题,URL)、history.replaceState(),可以在不进行刷新的情况下操作历史记录。不同的是,前者是增加历史记录,后者是替换当前历史记录

  • 对比:hash兼容性更好;history更正式,可以设置与当前url同源的任意url,路径更美观;基于hash的路由不用对服务器做改动,history的路由要对服务器做相应配置。

    • ⭐️⭐️hash会检测#之后的路径,如果发现一致,不会重新加载,只有但与之前是不一样才会触发记录添加到栈中;history可以反复重新加载同一个页面,pushState也会添加到栈中

    • pushState设置的新url可以与当前url同源的任意url;hash只可修改#后面的部分,所以只可设置与当前同文档的url

    • pushState通过stateObject可以添加任意类型的数据到记录中;hash只可以添加短字符

    • pushState可以额外设置title属性供后续使用

  • abstract:非浏览器

  • 关于history的一个问题:单页应用的理想场景是,仅在进入应用时加载index.html,后续的网络操作通过ajax完成,不会根据url重新请求页面,但是难免遇到特殊情况:用户在地址栏输入地址并回车,浏览器重新加载应用等;

    1. hash模式仅改变hash部分的内容,hash部分不会包含在http请求中:http://oursite.com/#/user/id//如果重新请求只会发送http://oursite.com/,所以hash模式下遇到根据url请求页面的情况不会有问题

    2. history模式会将url修改得和正常请求后端的url一样http://oursite.com/user/id,在此情况下向后端发送请求,如果后端没有配置对应的user/id路由处理,就会返回404错误

    3. ⭐️官方推荐的解决方法:在服务端增加一个覆盖所有情况的候选资源:如果url匹配不到任何静态资源,则应该返回同一个index.html页面,这个页面就是App依赖的页面。这样服务器就不会返回404错误页面,因为对所有页面都返回index.html文件。为了应对这种情况,在vue应用里面覆盖所有的路由情况,然后给出一个404页面,或者,如果使用nodejs做后台,可以使用服务端的路由来匹配url,当没有匹配到路由时返回404,从而实现fallback。

- hash & history 前端路由实现方式

更新视图但不重新请求页面”是前端路由原理的核心

模式参数:

vue-router中通过mode来控制路由的实现模式

  • mode只是一个标记,mode:history: HashHistory | HTML5History | AbstractHistory;根据history的类别执行相应的初始化操作和监听;VueRouter类暴露的以下方法实际是调用具体history对象的方法(push & replace

  • 初始化history前,会进行校验,浏览器不支持HTML5History(通过suportsPushState变量判断)则强制为hash模式,非浏览器环境为abstract模式

hash模式:

  • 改变hash不会重新加载页面,不会被包含在http请求中,指导浏览器动作的

  • 为hash的改变添加监听事件:window.addEventListener("hashchange", funcRef, false)

  • 每一次改变hash(window.location.hash),都会在浏览器的访问历史中增加一个记录

  • $router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()

  • replace()方法与push()方法不同之处:不是直接对window.location.hash进行赋值,而是调用window.location.replace方法将路由进行替换

  • 监听地址栏:我们可以通过输入URL访问,因此要添加路由监听并触发响应行为 通过setupListeners实现

setupListeners () {
     window.addEventListener('hashchange', () => {
     if (!ensureSlash()) {
     return
     }
     this.transitionTo(getHash(), route => {
     replaceHash(route.fullPath) // 相当于调用了replaceHash
     })
     })
    }

history模式:

History interface是浏览器历史记录栈提供的接口,通过back(), forward(), go()等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。

新的方法:pushState(), replaceState()对浏览器历史记录栈进行修改:

window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)

代码结构以及更新视图的逻辑与hash模式基本类似,只不过将对window.location.hash直接进行赋值window.location.replace()改为了调用history.pushState()history.replaceState()方法。

abstract模式:

原理为用一个数组stack模拟出浏览器历史记录栈的功能。

history VS hash

  • ·pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL

  • pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中

  • pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串

  • pushState可额外设置title属性供后续使用

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

推荐阅读更多精彩内容