Open chiwent opened 5 years ago
对于用户来说,路由就是浏览器地址栏中的url;而对于开发者来说,路由主要的工作是匹配url和对应的处理函数,访问的url会映射到对应的函数中。简单的说,路由就是UTL到函数的映射。
在早期的web开发中,后端MVC是主流的开发模式,比如PHP、JSP之类的,后端会将模板渲染成HTML返回到浏览器,用户是通过URL访问到对应的页面,后端匹配到路由后就返回对应的HTML。在切换不同的页面(路由)时,前端都会向后端重新发出一次请求。而如果遇到了无法匹配的路由,后端则会返回404状态码。 后端路由的问题: 在切换路由的时候,浏览器需要向后端重新发起一次请求,全局刷新加上网络延迟,会破坏用户体验(尽管可以用ajax一定程度上缓解)。
往后,web开发进入单页应用(SPA)时代,浏览器在向服务端发起请求后,服务端会向浏览器发送一个简单的HTML模板文件和一些js依赖文件,然后由浏览器解析js并将数据注入到HTML中。这样可以使页面的响应速度更快,体验更友好。在SPA应用中,页面跳转的规则交由前端控制,在切换路由时,不需要向后端发送请求,只要解析js即可。
前端路由的问题: 使用浏览器的前进后退按键,会向后端重新发起请求,没有合理使用缓存。 无法记住滚动的位置,不能在使用前进后退按键时,返回原来的页面位置(比如在页面使用锚点的时候)
前端路由可以分为hash路由和history路由,其中hash路由的URL中带有#,后面会形成一个hash,可以通过window.location.hash拿到对应值。当URL中的hash值发送改变,会触发hashchange注册的回调,然后执行不同的操作。每次hash值的变动,都会在浏览器的访问历史中增加一个记录,可以通浏览器的前进后退来控制hash切换(会重新发起请求)。hash路由的兼容性好;history路由利用H5的history对应的API来完成路由控制,不会带有#,但兼容性较差,并且需要后台的配合,否则在不匹配的情况下会返回404。
#
window.location.hash
hashchange
触发hash值变动的方式有两种:
location.hash
location.hash = '#index
<body> <ul> <li><a href="#/">Index</a></li> <li><a href="#/album">Album</a></li> <li><a href="#/cate">category</a></li> </ul> <script> function HashRouter() { // 以键值对性质存储路由 this.routes = {}; // 当前路由URL this.currentUrl = ''; } // 存储更新的path路径和对应的回调,回调负责hash更新后的事务 HashRouter.prototype.route = function(path, callback) { this.routes[path] = callback || function(){}; }; // 执行当前url对应的回调, 刷新页面 HashRouter.prototype.refresh = function() { // 获取当前URL中的hash路径 this.currentUrl = location.hash.slice(1) || '/'; this.routes[this.currentUrl](); }; // 监听浏览器url hash更新 HashRouter.prototype.init = function() { window.addEventListener('load', this.refresh.bind(this), false); window.addEventListner('hashchange', this.refresh.bind(this), false); }; window.HashRouter = new HashRouter(); window.HashRouter.init(); HashRouter.route('/', function() { // 切换路由的操作 }); HashRouter.route('/album', function() { // 切换路由的操作 }); HashRouter.route('/cate', function() { // 切换路由的操作 }); </script> </body>
history路由主要是通过H5的history对象实现的,设计的API主要是history.pushState、history.replaceState和history.popState,其中前两者可以修改URL地址,而最后的事件可以监听地址变化,并且手动pushState并不会触发popState。
history.pushState
history.replaceState
history.popState
pushState和replaceState都接收3个参数,格式:window.history.pushState(stateObj, title, url)
window.history.pushState(stateObj, title, url)
<body> <ul> <li><a href="/">Index</a></li> <li><a href="/album">Album</a></li> <li><a href="/cate">category</a></li> </ul> <script> function HisoryRouter() { this.routes = {}; } HistoryRouter.prototype.init = function(path) { history.replaceState({ path: path }, null, path); this.routes[path] && this.routes[path](); } HistoryRouter.prototype.route = function(path, callback) { this.routes[path] = callback || function(){}; } HistoryRouter.prototype.go = function(path) { history.pushState({ path: path }, null, path); this.routes[path] && this.routes[path](); } HistoryRouter.prototype.onPopState = function () { window.addEventListener('popstate', function(e) { var path = e.state && e.state.path; this.routes[path] && this.routes[path](); }); } window.HistoryRouter = new HistoryRouter(); window.HistoryRouter.init(); HistoryRouter.route('/', function() { // 切换路由的操作 }); HistoryRouter.route('/album', function() { // 切换路由的操作 }); HistoryRouter.route('/cate', function() { // 切换路由的操作 }); </script> </body>
目前有很多MVVM前端框架都配备了对应的前端路由工具,如Vue下的VueRouter。在使用VueRouter的时候,默认选择的是hash模式,如果要使用history模式,可以在对配置进行修改。另外,由于浏览器的路由跳转是交给前端路由控制了,所以后端将不处理404的错误界面,因为服务端会对所有路径都返回那一个HTML模板文件。所以,为了要在前端正确处理404,应该加上如下配置:
const router = new VueRouter({ mode: 'history', routes: [{ path: '*', component: NotFoundPage }] });
或者像下面那样处理(较繁琐):
// https://blog.csdn.net/weixin_37861326/article/details/82383465 import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) // 404 import Errorinfo from '@/components/error404' const router = new Router({ routes: [ // 404page { path: '/errorinfo', name: 'Errorinfo', component: Errorinfo } ], scrollBehavior(to, from, savedPosition) { return { x: 0, y: 0 } }, history: true }) router.beforeEach((to, from, next) => { if (to.matched.length === 0) { from.name ? next({ name: from.name }) : next('/errorinfo'); } else { next(); //如果匹配到正确跳转 } }); export default router;
参考:
谈谈前端路由
什么是路由
对于用户来说,路由就是浏览器地址栏中的url;而对于开发者来说,路由主要的工作是匹配url和对应的处理函数,访问的url会映射到对应的函数中。简单的说,路由就是UTL到函数的映射。
什么是前端路由,什么是后端路由
在早期的web开发中,后端MVC是主流的开发模式,比如PHP、JSP之类的,后端会将模板渲染成HTML返回到浏览器,用户是通过URL访问到对应的页面,后端匹配到路由后就返回对应的HTML。在切换不同的页面(路由)时,前端都会向后端重新发出一次请求。而如果遇到了无法匹配的路由,后端则会返回404状态码。
后端路由的问题:
在切换路由的时候,浏览器需要向后端重新发起一次请求,全局刷新加上网络延迟,会破坏用户体验(尽管可以用ajax一定程度上缓解)。
往后,web开发进入单页应用(SPA)时代,浏览器在向服务端发起请求后,服务端会向浏览器发送一个简单的HTML模板文件和一些js依赖文件,然后由浏览器解析js并将数据注入到HTML中。这样可以使页面的响应速度更快,体验更友好。在SPA应用中,页面跳转的规则交由前端控制,在切换路由时,不需要向后端发送请求,只要解析js即可。
前端路由的问题:
使用浏览器的前进后退按键,会向后端重新发起请求,没有合理使用缓存。
无法记住滚动的位置,不能在使用前进后退按键时,返回原来的页面位置(比如在页面使用锚点的时候)
前端路由的实现
前端路由可以分为hash路由和history路由,其中hash路由的URL中带有
#
,后面会形成一个hash,可以通过window.location.hash
拿到对应值。当URL中的hash值发送改变,会触发hashchange
注册的回调,然后执行不同的操作。每次hash值的变动,都会在浏览器的访问历史中增加一个记录,可以通浏览器的前进后退来控制hash切换(会重新发起请求)。hash路由的兼容性好;history路由利用H5的history对应的API来完成路由控制,不会带有#
,但兼容性较差,并且需要后台的配合,否则在不匹配的情况下会返回404。hash路由的简单实现
触发hash值变动的方式有两种:
location.hash
,比如location.hash = '#index
history路由的简单实现
history路由主要是通过H5的history对象实现的,设计的API主要是
history.pushState
、history.replaceState
和history.popState
,其中前两者可以修改URL地址,而最后的事件可以监听地址变化,并且手动pushState并不会触发popState。pushState和replaceState都接收3个参数,格式:
window.history.pushState(stateObj, title, url)
目前有很多MVVM前端框架都配备了对应的前端路由工具,如Vue下的VueRouter。在使用VueRouter的时候,默认选择的是hash模式,如果要使用history模式,可以在对配置进行修改。另外,由于浏览器的路由跳转是交给前端路由控制了,所以后端将不处理404的错误界面,因为服务端会对所有路径都返回那一个HTML模板文件。所以,为了要在前端正确处理404,应该加上如下配置:
或者像下面那样处理(较繁琐):
参考: