文章目录
- 路由
- $router 和 $route
- 路由模式
- Hash 模式(默认)
- History 模式
- abstract 模式
- 动态路由
- 路由传参
- 路由守卫
- 参数
- 全局守卫
- 路由守卫
- 组件内守卫
- 执行顺序
路由
$router 和 $route
$router 是 Vue.js 中的路由器对象,用于管理路由。它包含了许多方法,例如 push、replace、go 等等,用于在路由之间进行导航。下面是一些常用的方法:
- push(location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void:跳转到一个新的页面,会向 history 栈添加一个新的记录;
- replace(location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void:跳转到一个新的页面,不会向 history 栈添加一个新的记录,而是替换当前的记录;
- go(n: number): void:在 history 栈中向前或向后移动 n 步;
- back(): void:向后退一步,相当于 go(-1);
- forward(): void:向前进一步,相当于 go(1)。
除了上述的方法以外,$router 还有一些其他的属性和方法,例如 currentRoute、beforeEach、afterEach 等等。这些属性和方法可以让我们更加方便地管理路由。
$route 是 Vue.js 中的当前路由对象,用于获取当前路由的信息。它包含了许多属性,例如 path、params、query、hash 等等,用于描述当前路由的状态。下面是一些常用的属性:
- path:当前路由的路径;
- params:当前路由的参数,例如 /user/:id 中的 id;
- query:当前路由的查询参数,例如 /user?id=123 中的 id;
- hash:当前路由的哈希值,例如 /user#profile 中的 profile。
除了上述的属性以外,$route 还有一些其他的属性和方法,例如 name、meta、fullPath 等等。这些属性和方法可以让我们更加方便地获取当前路由的信息。
路由模式
传统的路由指的是:当用户访问一个 url 时,对应的服务器会接收这个请求,然后解析url 中的路径,从而执行对应的处理逻辑。这样就完成了一次路由分发。
而单页应用是在移动互联时代诞生的,它的目标是不刷新整体页面,通过地址栏中的变化来决定内容区域显示什么内容。要达成这个目标,我们要用到前端路由技术,具体来说有两种方式来实现:hash 模式和 history 模式。hash 模式是通过监听hashChange 事件来实现的,history 模式是通过 pushState/replaceState 方法+popstate 事件来实现的。
Hash 模式(默认)
不够美观,服务端无法获取 hash 值不利于 seo 优化
-
URL中永远带有
#
。如
http://www.example.com/#/about
。 -
当
#
后的部分发生变化时,不会向服务器发送请求。对后端完全没有影响,因此改变 hash 不会重新加载页面。
-
使用
window.onhashchange
来监听路由变化。路由的哈希模式其实是利用了 window.onhashchange 事件,也就是说你的 url 中的哈希值(#后面的值)如果有变化,就会自动调用 hashchange 的监听事件,在hashchange 的监听事件内可以得到改变后的 url,这样能够找到对应页面进行加载。
History 模式
-
URL中不带
#
,可以像普通网站链接一样。如
http://www.example.com/about
。 -
浏览器的历史记录中可以保存真实的 URL。
-
需要服务器支持,否则页面会 404。
History Interface 中除了支持 forward(),back(),go(),HTML5 History Interface 中新增的两个神器 pushState() 和 replaceState() 方法(对浏览器的兼容性有要求(IE >= 10)),作用就是可以将 url 替换并且不刷新页面。好比挂羊头卖狗肉,http 并没有去请求服务器该路径下的资源。一旦刷新就会暴露这个实际不存在的“羊头”,显示 404(因为浏览器一旦刷新,就是去真正请求服务器资源)。这就需要服务器端做点手脚,将不存在的路径请求重定向到入口文件(index.html),前后端联手,齐心协力做好“挂羊头卖狗肉”的完美特效。前端也需要在路由最后自己增加一个匹配‘*’,匹配所有其他路由,自定义自己的 notFound.vue 组件
pushState 方法、replaceState 方法,只能导致 history 对象发生变化,从而改变当前地址栏的 URL,但浏览器不会向后端发送请求,也不会触发 popstate 事件的执行。popstate 事件的执行是在点击浏览器的前进后退按钮的时候,才会被触发。
history 模式是通过调用 history.pushState方法(或者 replaceState) 并且监听 popstate 事件来实现的。history.pushState 会追加历史记录,并更换地址栏地址信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,并在处理函数内部决定跳转逻辑;监听 popstate 事件是为了响应浏览器的前进后退功能。
abstract 模式
适用于所有 JavaScript 环境,例如服务器端使用 Node.js。如果没有浏览器 API,路由器将自动被强制进入此模式。
可实现在不改变当前页面 path 的前提下加载其他路由中的 views 了。
// 使用hash模式
const router = new VueRouter({mode: 'hash',routes: [{ path: '/', component: Home },{ path: '/about', component: About }]
})// 使用history模式
const router = new VueRouter({mode: 'history',routes: [{ path: '/', component: Home },{ path: '/about', component: About }]
})
动态路由
path/:user/:id`
`$route.params.id
路由传参
query 可以用 name 或者 path 跳转路由;params 传参只能用 name 跳转路由。
params 传参可以显示参数也可以不显示参数,不显示参数页面刷新参数会丢失。
-
query 传参
<!-- 写法一 --> <router-link to="/login?id=9&level=2">登录</router-link> <!-- 写法二 --> <router-link :to="{path: '/login', query:{'id' : 9, 'level' : 2}}">登录</router-link> <!-- 写法三 --> <router-link :to="{naem: 'login', query:{'id' : 9, 'level' : 2}}">登录</router-link>
-
params 传参
-
url 显示参数
<router-link to="/login/11">登录</router-link>
// 路由定义时需要动态接受参数 const router = new VueRouter({routes:[{path:'/login/:id',component:login},] })
-
url 不显示参数
// 注意:利用 params 不显示 url 传参的方式会导致在刷新页面的时候,传递的值会丢失; <router-link :to="{name:'Log',params:{num:123}}">显示登录页面</router-link>
-
路由守卫
参数
-
to 参数:表示即将跳转到的路由对象。它包含了目标路由的信息,如路径、参数、查询参数等。
to.path
:目标路由的路径。to.params
:目标路由的参数对象。to.query
:目标路由的查询参数对象。to.fullPath
:完整的目标路由路径,包含参数和查询参数。
-
from 参数:表示当前导航正要离开的路由对象。它也包含了当前路由的信息。
from.path
:当前路由的路径。from.params
:当前路由的参数对象。from.query
:当前路由的查询参数对象。from.fullPath
:完整的当前路由路径,包含参数和查询参数。
-
next 参数:是一个函数,用于控制路由跳转的行为。它可以接收一个参数,用于指定要跳转的目标路由路径或一个 false 值来取消导航。
next()
:表示允许路由跳转。next(false)
:表示取消路由导航。next('/')
:表示重定向到指定路径。next({...})
:表示重定向到指定路由对象,对象支持的属性和to对象的属性一致。next(error) (2.4.0+)
: 导航会被终止且该错误会被传递给router.onError()
注册过的回调。
确保要调用 next 方法,否则钩子就不会被 resolved。
全局守卫
router.beforeEach
: 在路由跳转前执行的操作,可以在这里进行权限验证、登录判断等。router.afterEach
: 在路由跳转后执行的操作。这些钩子不会接受 next 函数也不会改变导航本身。router.beforeResolve
(2.5 新增): 在导航被确认之前,所有组件内守卫和异步路由组件被解析之后调用。
import { createRouter, createWebHistory } from 'vue-router'const router = createRouter({history: createWebHistory(),routes: [...]
})router.beforeEach((to, from, next) => {// 在这里进行权限验证、登录判断等操作next() // 跳转到下一个路由
})router.afterEach(() => {// 跳转后的操作
})router.beforeResolve((to, from, next) => {// 在导航被确认之前的操作next()
})export default router
路由守卫
beforeEnter
: 在路由进入前执行的操作。beforeLeave
: 在路由离开前执行的操作。
const router = new VueRouter({routes: [{path: '/foo',component: Foo,beforeEnter: (to, from, next) => {// ...},beforeLeave: (to, from, next) => {// ...}}]
})
组件内守卫
beforeRouteEnter
:在路由进入前执行的操作,但是在组件实例被创建之前调用。是支持给next 传递回调
获取当前实例对象的唯一守卫。一般用于动态导航时获取参数进行页面逻辑的区分。beforeRouteUpdate
:在路由更新时执行的操作。参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察$route
对象来应对这些变化,或使用beforeRouteUpdate
的组件内守卫。beforeRouteLeave
:路由离开守卫,通常用来禁止用户在还未保存修改前突然离开,该导航可以通过next(false)
来取消。也可以清除一些内存泄漏的操作。也保存相关内容到Vuex中或Session中。
const Foo = {template: `...`,// 在渲染该组件的对应路由被 confirm 前调用// 不!能!获取组件实例 `this`// 因为当守卫执行前,组件实例还没被创建//不过,你可以通过传一个回调给 next来访问组件实例。//在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。beforeRouteEnter (to, from, next) {next(vm => {// 通过 `vm` 访问组件实例})},beforeRouteUpdate (to, from, next) {// 在当前路由改变,但是该组件被复用时调用// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。// 可以访问组件实例 `this`},beforeRouteLeave (to, from, next) {// 导航离开该组件的对应路由时调用// 可以访问组件实例 `this`}
}
执行顺序
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。