写在前面
用户进行了交互操作,现在要对页面内容进行变更,可以通过javascript进行动态替换DOM,但是其不便于分享、收藏,对于搜索引擎和用户来说都是不友好的!
什么是前端路由?
根据不同的 url 地址展示不同的内容或页面,无需依赖服务器根据不同URL进行页面展示操作
优点
- 用户体验好,不需要每次都从服务器全部获取,快速展现给用户
缺点
- 使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存
- 单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置
简介
使用 Vue.js ,可以通过组合组件来组成应用程序,当你要把 vue-router 添加进来,我们需要做的是,将组件(components)映射到路由(routes),然后告诉 vue-router 在哪里渲染它们。
动态路由匹配
两种方式传递$route.params
和$route.query
模式 | 匹配路径 | 获取参数(路由信息对象) |
/user/:username | /user/ligang | |
/user?:username | /user?username=ligang | |
响应路由参数的变化
当使用路由参数时,例如从 /user/ligang
导航到 user/lg
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
方式一:简单地watch(监测变化)$route对象
方式二:使用 2.2 中引入的 beforeRouteUpdate
守卫
示例:新增和编辑使用同一模块,从编辑切换到新增页面信息不会更新!
嵌套路由
要注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
编程式导航
router.push(location, onComplete?, onAbort?)
声明式 | 编程式 |
| |
注意:如果提供了 path,params 会被忽略,query不会!!
router.replace(location, onComplete?, onAbort?)
声明式 | 编程式 |
| |
跟router.push
很像,唯一的不同就是,它不会向 history 添加新记录!
router.go(n)
在 history 记录中向前或者后退多少步,类似 window.history.go(n)
命名视图
多个非嵌套视图展示,例如创建一个布局,有header
头信息、 sidebar
(侧导航) 和 main
(主内容) 两个视图。
重定向和别名
重定向
别名
/a
的别名是/b
,意味着当用户访问/b
时,URL会保持为/b
,但是路由匹配则为/a
,就像用户访问/a
一样。
『别名』的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。
示例:上述【动态路由匹配】可修改成如下,可能存在name问题
向路由组件传递 props
路由组件传参
默认(常规)方式:通过$route.params获取
使用props解耦:只需要将props设置为true
注意:上述props不仅可以设置为布尔值,还可以设置为对象或函数,具体请查看:「https://router.vuejs.org/zh-cn/essentials/passing-props.html」
HTML5 History 模式
需要后台配置,否则输入的除首页外都为404(当然系统内跳转可以)。具体ngix、Apache、node等配置参考:「https://router.vuejs.org/zh-cn/essentials/history-mode.html」
这里说一下本地webpack需要增加的配置情况:historyApiFallback: true
「https://doc.webpack-china.org/configuration/dev-server/#devserver-historyapifallback」vue-cli生成的默认webpack配置,
在window下特定node版本会有问题!
导航守卫
『导航』表示路由正在发生改变
导航守卫主要用来通过跳转或取消的方式守卫导航。注意参数或查询的改变并不会触发进入/离开的导航守卫。可以通过观察 $route来应对这些变化,或使用 beforeRouteUpdate
的组件内守卫。
全局守卫
使用 router.beforeEach
注册一个全局前置守卫
守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。所以确保要调用 next 方法,否则钩子就不会被 resolved。
全局解析守卫
在 2.5.0+ 你可以用 router.beforeResolve
注册一个全局守卫。这和 router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next
函数也不会改变导航本身:
路由独享的守卫
组件内的守卫
-
beforeRouteEnter
-
beforeRouteUpdate
(2.2 新增) -
beforeRouteLeave
需要注意的是beforeRouteEnter不能访问this,可以通过传一个回调给 next
来访问组件实例。
完整的导航解析流程
- 导航被触发。
- 在失活的组件内调用离开守卫
beforeRouteLeave
。 - 调用全局的
beforeEach
守卫。 - 在重用的组件内调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用独享守卫
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件内调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 用创建好的实例调用
beforeRouteEnter
守卫中传给 next
的回调函数。
路由元信息
meta
字段来设置名称、是否需要验证、是否隐藏等附加信息!!
一个路由匹配到的所有路由记录会暴露为 $route
对象(还有在导航守卫中的路有对象)的 $route.matched
数组。因此,我们需要遍历 $route.matched
来检查路由记录中的 meta
字段。
数据获取
有时候,进入某个路由后,需要从服务器获取数据。
- 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示『加载中』之类的指示。
该方式会马上导航和渲染组件,然后在组件的 created
钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态。 - 导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
该方式在导航转入新的路由前获取数据。我们可以在接下来的组件内的 beforeRouteEnter
守卫中获取数据,当数据获取成功后只调用 next
方法。
滚动行为
只在 HTML5 history 模式下可用。当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router
能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
参考地址:「https://router.vuejs.org/zh-cn/advanced/scroll-behavior.html」
特别说明
Router 实例
属性 | 说明 |
router.app | |
router.mode | 路由使用的模式 |
router.currentRoute | 当前路由对应的路由信息对象 |
方法:router.beforeEach(guard)、router.beforeResolve(guard) 、router.afterEach(hook)、router.push(location, onComplete?, onAbort?)、router.replace(location, onComplete?, onAbort?)、router.go(n)、router.back()、router.forward()、router.getMatchedComponents(location?)、router.resolve(location, current?, append?)、router.addRoutes(routes)、router.onReady(callback, [errorCallback])、router.onError(callback)
路由信息对象
每次成功的导航后都会产生一个新的对象
- 在组件内,即
this.$route
- 在
$route
观察者回调内 -
router.match(location)
的返回值 - 导航守卫的参数:
-
scrollBehavior
方法的参数:
其包含的属性值:route.path、route.params、route.query、route.hash、route.fullPath、route.matched
重点强调:this.router.currentRoute===this.route
行为表现
因为它也是个组件,所以可以配合 <transition>
和 <keep-alive>
使用。如果两个结合一起用,要确保在内层使用 <keep-alive>
:
router-link
<router-link>
比起写死的 <a href="...">
会好一些,理由如下:
- 无论是 HTML5 history 模式还是 hash 模式,它的表现行为一致,所以,当你要切换路由模式,或者在 IE9 降级使用 hash 模式,无须作任何变动。
- 在 HTML5 history 模式下,
router-link
会守卫点击事件,让浏览器不再重新加载页面。 - 当你在 HTML5 history 模式下使用
base
选项之后,所有的 to
属性都不需要写(基路径)了。
base相关说明:「https://router.vuejs.org/zh-cn/api/options.html#base」
实例
header编写
第一步:获取router的全部配置信息import {ROUTES} from '@/app.router'
,然后循环铺值(获取一级的路由)meta.name
第二步:选择header,路由跳转;主要思路:在一级组件上配置meta.defaultRouteName
信息,获取该信息后,进行调整(如果不含有该信息,则默认第一个子路由)
第三步:处理当前选中的的header项目
sidebar编写
基本思路和header相似,唯一区别是要根据当前一级路由进行铺值!