每日一题-你所理解的前端路由是什么?
- 为什么会出现前端路由
- 前端路由解决了什么问题
- 前端路由实现的原理是什么
传统页面
整个项目都是 DOM直出的页面,“传统页面”(SSR 属于首屏直出,这里我不认为是传统页面的范畴)。那么什么是 DOM直出呢?简单说就是在浏览器输入网址后发起请求,返回来的 HTML页面是最终呈现的效果,那就是 DOM 直出。并且每次点击页面跳转,都会重新请求 HTML 资源。
个传统页面搭建而成的网站,每次加载页面,都会返回 HTML 资源以及里面的 CSS 等静态资源,组合成一个新的页面。
单页面
React 、 Vue 、 Angular 等著名单页面应用框架。而这些框架有一个共同的特点,便是“通过 JS 渲染页面”。运用这些单页面框架之后, HTML 页面基本上只有一个 DOM 入口
既然单页面是这样渲染的,那如果我有十几个页面要互相跳转切换,咋整!!??这时候 前端路由 应运而生,它的出现就是为了解决单页面网站,通过切换浏览器地址路径,来匹配相对应的页面组件。我们通过一张丑陋的图片来理解这个过程
前端路由 会根据浏览器地址栏 pathname 的变化,去匹配相应的页面组件。然后将其通过创建 DOM 节点的形式,塞入根节点 <div id="root"></div> 。这就达到了无刷新页面切换的效果,从侧面也能说明正因为无刷新,所以 React 、 Vue 、 Angular 等现代框架在创建页面组件的时候,每个组件都有自己的 生命周期。
原理:哈希模式a 标签锚点大家应该不陌生,而浏览器地址上 # 后面的变化,是可以被监听的,浏览器为我们提供了原生监听事件 hashchange ,它可以监听到如下的变化:
- 点击 a 标签,改变了浏览器地址
- 浏览器的前进后退行为
- 通过 window.location 方法,改变浏览器地址
历史模式 history 模式会比 hash 模式稍麻烦一些,因为 history 模式依赖的是原生事件 popstate ,下面是来自 MDN 的解释:
需要注意的是 调用 history.pushState() 或 history.replaceState() 不会触发popstate事件,只有在做出浏览器动作时,才会触发该时间,如果用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back()或者 history.forward()方法。
小知识:pushState 和 replaceState 都是 HTML5 的新 API,他们的作用很强大,可以做到改变浏览器地址却不刷新页面。这是实现改变地址栏却不刷新页面的重要方法。
包括 a 标签的点击事件也是不会被 popstate 监听。我们需要想个办法解决这个问题,才能实现 history 模式。
解决思路:我们可以通过遍历页面上的所有 a 标签,阻止 a 标签的默认事件的同时,加上点击事件的回调函数,在回调函数内获取 a 标签的 href 属性值,再通过 pushState 去改变浏览器的 location.pathname 属性值。然后手动执行 popstate 事件的回调函数,去匹配相应的路由
为什么需要前端路由?
以前传统的前端都是一个URL对应一个页面,所以不存在这个问题。随着SPA(single-page application)即单页应用的发展,组件的变化和更新不再对应着URL变化了。但是我们又需要这种对应关系(比如通过一个URL直接访问一个 SPA 应用的子视图),我们急需一个工具专门负责维护组件状态与页面URL之间的对应关系,这就是前端路由的作用所在,如 react 的 react-router 和 vue 的 vue-router。
解决问题:
它的出现主要是为了解决单页网站,通过切换浏览器地址url路径,来匹配相对应的页面组件。
使用场景:在单页面应用中,大部分页面结构不变,只改变部分内容时使用。
前端路由优缺点
优点:用户体验好,页面初始化后,只需根据路由变换页面内容,不需要再向服务器发送请求,内容变换快,实现了前后端分离。
缺点:使用浏览器的前进、后退键的时候会重新发送请求,没合理的利用缓存;单页面无法记住之前滚动的位置,无法在前进、后退时记住滚动的位置。
实现原理?
1、哈希模式 #hash
这个模块主要关注 location.hash值,可以通过事件 hashchange 监听 URL的变化,从而跳转到对应的子页面。
2、历史模式
这个模式主要关注 。 location.pathname的值,可以通过事件 popstate 监听URL,但是它有很多局限性,只要做出浏览器动作如用户点击来会退按钮或在JavaScript中调用了 history.back() / history.forward() 才会触发事件,下面这些情况不会触发 popstateshijian :
- pushState,replaceState(HTML5的心API改变地址栏而不引起页面变化)
- a标签的点击事件
解决思路:
遍历DOM中所有的a标签,监听click事件,手动pushState改变浏览器地址,并手动调用popState中的回调函数。
参考:https://blog.csdn.net/m0_46171043/article/details/112796220
参考:https://www.jianshu.com/p/29fb3ec0611c