路由
路由就是分发请求
路由器就是分发请求的东西
维基百科--路由
-
路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。
-
路由引导分组转送,经过一些中间的节点后,到它们最后的目的地。作成硬件的话,则称为路由器Router。
-
路由表:一个存储到各个目的地的最佳路径的表
-
路由通常根据路由表来引导分组转送。因此为了有效率的转送分组,创建存储在路由器存储器内的路由表是非常重要的。
hash:#1
默认路由:啥都不写的时候
404路由(保底路由):写错的时候
嵌套路由
路由的hash模式
- 通过url存路径。只不过用的是url的哈希
- baidu.com/#1
- 从window.location.hash获取#号后的,如1
- 任何情况都可以用hash做前端路由
- 缺点:SEO不友好
- 浏览器是不会把#后的内容发给服务器的,服务器收不到哈希
如在浏览器输入baidu.com/#1 其实请求的url:baidu.com
谷歌推出了一款hashbang来解决这个SEO不友好的问题。但是还是没啥用。 数字
- vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
路由的history模式
- 通过url存路径。只不过用的是url的路径
- 直接用路径baidu.com/1
- 从window.location.pathname获取路径,如/1
- 只有一种情况下可以使用:后端将所有前端路由都渲染同一个页面(不能是404) + 不支持IE8
- 后端做到:不管输入baidu.com/1还是baidu.com/2,都进入的是一个页面
- 缺点:IE8不支持
路由的memory模式
-
不是url存路径
-
前端存到localStorage里,手机
-
从localStorage.getItem('xxx')获取
-
适合非浏览器,如手机app
-
weex和react native
-
缺点:不可以分享,因为不是用url,本来url都存了好多信息
$router和$route
- node_modules/vue-router/types/vue.d.ts里,写了下面代码,表示给Vue添加了这俩属性。因此我们可以在Vue实例/组件里使用
this.$route和this.$router
declare module 'vue/types/vue' {
interface Vue {
$router: VueRouter
$route: Route
}
}
$route获取当前路由信息
- 如
this.$route.params
$router路由器,用于重定向等
- 如
this.$router.replace('/404') - 如
this.$router.push('/404')
Vue Router常用
import Vue from 'vue'
import VueRouter from 'vue-router'
import Money from '@/views/Money.vue';
import Labels from '@/views/Labels.vue';
import Statistics from '@/views/Statistics.vue';
import NotFound from '@/views/NotFound.vue';
import EditLabel from '@/views/EditLabel.vue';
Vue.use(VueRouter);
//定义路由,每个路由应该映射一个组件。
const routes = [
{
path: '/',
redirect: '/money' //把根路径重定向到路径/money
},
{
path:'/money',
component:Money
},
{
path:'/labels',
component: Labels
},
{
path:'/statistics',
component: Statistics
},
//动态路径参数 以冒号开头
{
path: '/labels/edit/:id',
component: EditLabel
},
{
path:'*', //输入路径之后,每次都是从最上面的路径依次向下找有没有和输入的路径一样的。如果上面的都不是,那输入的路径就属于*(除去上面后的所有的路径)
component: NotFound
}
]
//创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes
})
export default router
//mian.ts
import router from './router'; //导入一个文件夹,如果这个文件夹有index文件,那就是导入的是index文件里
new Vue({
router, //把router传给Vue
store,
render: h => h(App)
}).$mount('#app');
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/money">Go to Money</router-link>
<router-link to="/labels">Go to Labels</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
动态路由匹配
- 我们有一个 EditLabel 组件,对于所有标签都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:
//动态路径参数 以冒号开头
{
path: '/labels/edit/:id',
component: EditLabel
},
- 一个“路径参数”使用冒号
:标记。当匹配到一个路由时,参数值会被设置到this.$route.params,可以在每个组件内使用。 - 比如模式是
/labels/edit/:id,若匹配路径是/labels/edit/1,那么$route.params就是{id:'1'}
Vue Router的history
如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
const router = new VueRouter({
mode: 'history',
routes: [...]
})
当你使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!
不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
Vue Router的路由对象
一个路由对象 (route object) 表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息,还有 URL 匹配到的路由记录 (route records)。
路由对象是不可变 (immutable) 的,每次成功的导航后都会产生一个新的对象。
路由对象出现在多个地方:
-
在组件内,即
this.$route -
在
$route观察者回调内 -
router.match(location) 的返回值
-
导航守卫的参数:
router.beforeEach((to, from, next) => {
// `to` 和 `from` 都是路由对象
})
- scrollBehavior 方法的参数:
const router = new VueRouter({
scrollBehavior(to, from, savedPosition) {
// `to` 和 `from` 都是路由对象
}
})
路由对象属性
导航守卫
导航守卫是什么
-
官方这么说:正如其名,vue-router提供的导航守卫主要用来通过跳转或取消的方式守卫导航。
-
翻译过来就是:导航守卫就是路由跳转过程中的一些钩子函数
-
再直白点:路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都有一函数,这个函数能让你操作一些其他的事儿的时机,这就是导航守卫
导航守卫分为三种:全局的、单个路由独享的、组件内
全局的
定义
- 是指路由实例上直接操作的钩子函数,他的特点是所有路由配置的组件都会触发,直白点就是触发路由就会触发这些钩子函数
- 钩子函数按执行顺序包括beforeEach、beforeResolve(2.5+)、afterEach三个
钩子
beforeEach:在路由跳转前触发,参数包括to,from,next三个,这个钩子作用主要是用于登录验证,也就是路由还没跳转提前告知,以免跳转了再通知就为时已晚。
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
-
beforeResolve: 在beforeEach和组件内beforeRouteEnter之后,afterEach之前调用 -
afterEach:和beforeEach相反,他是在路由跳转完成后触发,参数包括to,from没有了next(参数会单独介绍),他发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件内守卫,后讲)之前。
路由独享的
定义
- 是指在单个路由配置的时候也可以设置的钩子函数,其位置就是下面示例中的位置,也就是像Foo这样的组件都存在这样的钩子函数。
- 目前他只有一个钩子函数beforeEnter:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
钩子
beforeEnter :和beforeEach完全相同,在路由跳转前触发,如果他俩都设置则在beforeEach之后紧随执行,参数to、from、next
组件内的
定义
- 是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩子函数。
- 钩子函数按执行顺序包括beforeRouteEnter、beforeRouteUpdate (2.2+)、beforeRouteLeave三个,执行位置如下:
<template>
...
</template>
<script>
export default{
data(){
//...
},
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
<script/>
<style>
...
</style>
钩子
beforeRouteEnter:路由进入之前调用,参数包括to,from,next。该钩子在全局守卫beforeEach和独享守卫beforeEnter之后,全局beforeResolve和全局afterEach之前调用
- 要注意的是该守卫内访问不到组件的实例,也就是this为undefined,也就是他在beforeCreate生命周期前触发。
- 在这个钩子函数中,可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数,可以在这个守卫中请求服务端获取数据,当成功获取并能进入路由时,调用next并在回调中通过 vm访问组件实例进行赋值等操作,(next中函数的调用在mounted之后:为了确保能对组件实例的完整访问)。
beforeRouteEnter (to, from, next) {
// 这里还无法访问到组件实例,this === undefined
next( vm => {
// 通过 `vm` 访问组件实例
})
}
-
beforeRouteUpdate(v 2.2+): 在当前路由改变时,并且该组件被复用时调用,可以通过this访问实例。参数包括to,from,next。可能有的同学会疑问,what is 路由改变 or what is 组件被复用?
- 对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,组件实例会被复用,该守卫会被调用
- 当前路由query变更时,该守卫会被调用
beforeRouteLeave:导航离开该组件的对应路由时调用,可以访问组件实例this,参数包括to,from,next。
导航守卫回调参数
-
to:目标路由对象;
-
from:即将要离开的路由对象;
-
next:他是最重要的一个参数,他相当于佛珠的线,把一个一个珠子逐个串起来。以下注意点务必牢记:
-
但凡涉及到有next参数的钩子,必须调用next() 才能继续往下执行下一个钩子,否则路由跳转等会停止。
-
如果要中断当前的导航要调用next(false)。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from路由对应的地址。(主要用于登录验证不通过的处理)
-
当然next可以这样使用,next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。意思是当前的导航被中断,然后进行一个新的导航。可传递的参数与router.push中选项一致。
-
在beforeRouteEnter钩子中next((vm)=>{})内接收的回调函数参数为当前组件的实例vm,这个回调函数在生命周期mounted之后调用,也就是,他是所有导航守卫和生命周期函数最后执行的那个钩子。
-
next(error): (v2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
总结
我们最后屡一下顺序:
-
当点击切换路由时:beforeRouterLeave-->beforeEach-->beforeEnter-->beforeRouteEnter-->beforeResolve-->afterEach-->beforeCreate-->created-->beforeMount-->mounted-->beforeRouteEnter的next的回调
-
当路由更新时:beforeRouteUpdate