vue-router项目实战总结
今天来谈谈vue项目{vue,vue-router,component}三大神将之一的vue-router。作为我们前后端分离很重要的实践之一,router帮我们完成了SPA应用间的页面跳转。
并且,配合axios这样的第三方库,我们可以实现配合后台接口的拦截器功能。
对于一个小型项目而言,router这个文件夹里面就包含了一个router.js就足够了,但是,当我们的页面比较多的时候,我们就需要分出两个文件出来:一个定义我们的路由和组件,另一个实例化组件,并将路由挂载到vue的实例上。
基本的用法就不多赘述,大家可以看 vue-router 的官网,认真过一遍的话,基本使用肯定没什么问题。
1. 为什么我的路由不起作用?
这里有个非常重要的一点就是当我们去构造VueRouter的实例的时候,传入的参数的问题。
1 | import routes from "@/router/router"; |
如果你这里引入的不是routes,你就要按照下面的方式来写:
1 | import vRoutes from "@/router/router"; |
2. 在路由中基于webpack实现组件的懒加载
对于我们的vue项目,我们基本都是运用webpack打包的,如果没有懒加载,打包后的文件将会异常的大,造成首页白屏,延时严重,不利于用户体验。而运用懒加载则可以将页面进行划分,webpack将不同组件打包成很多个小的js文件,需要的时候再异步加载,优化用户的体验。
1 | import App from "@/App.vue"; |
如果某个组件包含了嵌套路由,我们也可以将两个路由打包到一个js chunk中:
1 | // 这两条路由被打包在相同的块中,访问任一路由都会延迟加载该路由组件 |
3. router的模式
对于浏览器,我们的router分为两种模式。
1. hash模式(默认)
按照一个uri的基本结构来说,hash模式就是在一个基本的URI的片段进行的处理。如果抛开SPA的话,比较常见的应用场景就是我们在做pc商城的时候,会有比如说:商品详情、评论、商品参数这样的tab切换,就可以使用a标签配合id使用,加上一点运动的特效,效果甚佳。
这也是router默认使用的路由方式。不过,这种方式有一个弊端,就是在接入第三方支付的时候,我们传入一个url给到第三方支付作为回调地址,但是在支付完成以后,有的第三方支付会把我们的#作为一个截取符号,仅保留第一个#符号前面的url内容,后面再添加相应的回调参数,导致支付完成以后无法跳转到相应的支付页面。
1 | 传入的url: |
2. history模式
还有一种就是history的模式。它是使用h5的history.pushState来完成URL的跳转的。使用这种方式来处理跳转的好处就是,url和我们平常看到的没有什么区别,和hash模式作比较的话就是没有了#。不过使用history模式,我们在后台也要去做相应的处理,因为如果直接去访问一个地址,例如http://www.xxxx.com/user/id的时候,如果后端没有配置,后端就会返回404页面。
4. router-link在循环中this.参数名=undefined
<router-link> 组件是我们在view层中需要用到的跳转组件。它替代了<a>标签需要做的事情,并且帮助我们做了更多的事情:
- 无论是 h5 history 模式还是 hash 模式,它的表现行为一致,所以,当你要切换路由模式,或者在 IE9 降级使用 hash 模式,无须任何变动。
- 在 HTML5 history 模式下,
router-link会守卫点击事件,让浏览器不再重新加载页面。 - 当你在 HTML5 history 模式下使用
base选项之后,所有的to属性都不需要写(基路径)了。
不过当我们在v-for的循环中使用了router-link的时候,如果需要取一个我们在data中定义的值,我们是通过this.foo来取呢?还是通过foo来取呢?
这里的话,我们是不能通过this.foo来取的,因为这里的this不再是指向vue的实例了,而是指向了[object Window]。所以用this.foo来取的话,其实是undefined。
1 | <router-link |
1 | data(){ |
5. vue-router配合axios的使用
初次接触拦截器这个概念是在java中,通过拦截器,我们可以对用户的登录状态进行更加粒度的操作。而对于一个SPA的应用来说,没有了后台路由的介入,我们就需要在前端实现一套自己的登录状态的管理机制。
最直观的一点就是,通过用户的token来判断用户是否登录:
1 | router.beforeEach((to, from, next) => { |
上面的代码中,我们通过vue-router中的全局守卫,在导航触发的时候大致做了如下几件事:
- 判断导航的页面是否需要登录
- 超过登录持久期限,清除持久化的登录用户token
- 没有超过登录期限,判断是否登录状态
- 没登录,重定向到登录页面
但是,仅仅这样是不够的。因为用户直接不正常注销而直接后台运行网页是很正常的事情,这就导致虽然token是存在的,但是对于后台而言,这个token是无效的、过期的了。所以,我们需要axios配合后台给出的状态码来完善我们的拦截器。
1 | import router from "@/router/routes"; |
通过后端给到的登录过期状态码(这里以-100为例),我们可以用axios的响应拦截器实现,当我们的token过期的时候,将页面重定向到登录页面去。
6. 巧用replace替换push
在项目中,有的同事就是一直this.$router.push(...),从开始push到结尾。
碰到有的页面,比如说,在选择地址的时候需要知道用户当前所在的城市,如果没有的话,就重定向到城市列表页面去手动选取。选择完成以后再回到选择地址的页面,如果一直使用push的话,点击选择地址的后退时,就会回退到城市列表页,造成页面间的死循环。
这里如果使用replace来操作就没有什么问题了,问题就是我们不应该让城市列表页出现在我们的浏览历史里面。