概念
路由器 router,整个应用共用一个路由器属性$router
路由 route,每个路由组件都有独立的路由属性$route
普通组件:路由没配置的组件
路由组件:路由配置的组件
标签
<router-link class="" to="/path" ></router-link> 默认会被渲染成一个a标签,阻止默认页面跳转行为。
to还可以传对象,包装path、name、params、query等,具体可以参考文档。
<router-view></router-view>路由组件会被渲染到这里
目录结构
普通组件放在components目录中
路由组件放在pages目录中
路由导航
除了上述提到的标签式路由导航,还有编程式路由导航。
例如:
this.$router.push({path:'/user/detail', query:{...}})
this.$router.replace({path:'/user/detail', query:{...}})push比较适合大的分类路由切换,基本就是切换业务场景了
replace比较适合细小的路由切换,比如当前业务场景下的子品类切换等
这样回退的时候可以一次回到上一个业务场景页面
路由组件
路由切换的时候,路由组件会被挂载,之前的路由组件默认会被销毁。可以用<keep-alive>包裹路由组件,缓存替代销毁。
路由组件获取值的方式:
- 组件内直接this.$route.query获取
- 组件内直接this.$route.params获取
- 比较推荐的是query传参,路由路径配置比较清晰,然后通过配置路由对象内的props属性,给路由组件以props形式传参
// 子路由配置中 children[ { name: 'aaa', path: 'detail', // 子路由路径开头不要加“/” component: Detail, props($route) { return { id: $route.query.id, title: $route.query.title } } } ]
对应的路由组件Detail只需要配置下props:['id', 'title']就可以在模板中方便使用了。
这样写的优点是路由配置相关都集中在一起,组件编码获取参数也不需要获取$route,各自分工明确,聚合性比较好。
利用缓存
<!--name属性指定的是组件名,指定缓存内容区的某个组件-->
<keep-alive name="formItemName">
<router-view></router-view>
</keep-alive>
使用keep-alive比较适合类似表单页签切换的场景,再配合$router.replace(),可以提高用户体验。
生命周期钩子:actived 和 deactived
actived:被 keep-alive 缓存的组件激活时调用。
deactived:被 keep-alive 缓存的组件失活时调用。
以上2个钩子需要配合keepalive标签使用。如果被缓存的组件已经隐藏了,有些行为例如setInterval等timer计时器的行为(或者其他定制业务行为)并不需要继续执行,可以考虑在actived和deactived钩子中加以控制。
actived() {
this.timer = setInterval(() => {
// ...
})
},
deactived() {
clearInterval(this.timer)
}
路由导航守卫
以下是路由守卫触发全流程,可以根据业务需求配置。
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。(router上配置)
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
浏览器hash模式和history模式
hash模式的地址栏会有一个”#“,后面跟各种路由路径和参数,此模式下浏览器不会将”#“和之后的内容发给服务器,也就是服务收到的请求地址只是”#“之前的部分。
因此如果前端使用了history模式,还想正常访问页面,就得需要后端(或者nginx)对请求的地址进行拦截处理。
例如nodejs可以npm安装connect-history-api-fallback
// 服务端项目
npm install connect-history-api-fallback
服务端处理请求代码(nodejs express)
const express = require('express')
const histroy = require('connect-history-api-fallback')
const app = express() // 创建一个服务
app.use(history()) // 注册history插件,可以根据history规则拆分请求地址
app.use(express.static(__dirname+'/static')) // 注册静态资源地址,这样就可以到前端页面了
// 配置接口
app.get('/user', (req, res) => {
req.send({
id: '001',
name: 'zhangsan'
})
})
app.listen(5000, err => {
if (!err) console.log('服务启动成功,端口:5000')
})
除了nodejs,我们还可以使用nginx进行反向代理,需要自己配置好正则规则
还可以使用java,也有专门的库支持history模式地址截取。
hash和history相比,hash的兼容性略好一点。vue-router默认使用的是”hash“模式,如果想改成history模式,需要把router的mode配置改成”history“。
vue-router的原理
理论基础
浏览器地址的改变会触发popstate事件;浏览器地址hash(#后面的部分)的改变会触发hashchange事件。这让我们可以监控到当前路由的变化;调用浏览器的api pushState或者js直接改变location.hash并不会触发页面跳转,只是地址栏地址发生了变化,这让我们可以实现api让浏览器地址改变。
基于上述特性,VueRouter向Vue注入组件后,就可以实现根据路由变化让Vue重新加载指定组件了。这就是所谓的路由跳转。
-
一是根据配置的模式(hash还是history)给window加事件监听(popstate或者hashchange)
html5.js
hash.js -
使用vue插件+mixin的方式,在beforeCreate()钩子里,往VueComponent实例上加了一个_route属性,用于存放当前路由对象,并且对此属性加了数据代理,地址变化会同步这里的属性。
index.js
install.js RouterView组件发现当前路由改变的时候(通过vue的数据代理),就会根据配置去加载指定的vueComponent从而实现了界面切换效果