前言
Vue
是单页面应用,在一个单页面中进入子页面或者跳转到其他页面离不开路由的帮助,与Vue
相辅的路由插件是vue-router
,如果让你手写vue-router
配置项或者排查一些问题,就需要扎实的基础。 并且vue-router4.x
都有了ts
类型定义,学习vue-router
也会对TS
学习有所帮助。
安装
CDN
xml
<script src="https://unpkg.com/vue-router@4"></script>
包管理器
对于一个现有的使用 JavaScript 包管理器的项目,你可以从 npm
中安装 Vue Router:
css
npm install vue-router@4
使用脚手架搭建
当然也可以直接通过脚手架搭建项目,选择安装Vue Router。大部分情况下,作者推荐这种搭建方式
sql
npm create vue@latest
使用
CDN导入方式的使用
html
<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-router@4"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件进行导航 -->
<!-- 通过传递 `to` 来指定链接 -->
<!-- `<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签 -->
<router-link to="/">Go to Home</router-link>
<router-link to="/about">Go to About</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
包管理器方式的使用
使用脚手架初始化后,我们会看的这么一个文件夹 其中router存放的是路由相关的文件 index.ts
ts
//用ES6解构导入
import { createRouter, createWebHistory } from "vue-router";
//可以直接导入组件
import HomeView from "../views/HomeView.vue";
// 定义路由
const routes = [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/about",
name: "about",
//也可以通过懒加载的方式
component: () => import("../views/AboutView.vue"),
},
];
const router = createRouter({
//使用history模式
//路由的3种模式会在以后的文章中详细讲解
history: createWebHistory(),
routes,
});
export default router;
main.ts
ts
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
//导入路由
import router from './router'
const app = createApp(App)
//挂载路由
app.use(router)
app.mount('#app')
这样就可以使用了
router-link
router-link是可以包裹链接的组件,跟a标签基本一样,并且它会在页面上渲染a标签。
相比于a标签,router-link不会在路由修改时重新加载页面,而且跳转链接只需要写相对路径就行。
我们看下源码,可以找到router-link会render成a标签。
ts
// 在组件的setup函数中:
// 1. 接收外部传递进来的props对象和this.$slots对象
setup(props, { slots }) {
// 2. 使用reactive包裹useLink函数的结果,使链接状态变为响应式数据
const link = reactive(useLink(props))
// 3. 从全局注入的router实例中获取路由选项
const { options } = inject(routerKey)!
// 4. 定义一个计算属性elClass,它会基于当前链接状态(如isActive, isExactActive)
// 以及用户自定义和全局路由选项中的类名,动态地返回一个CSS类名对象
const elClass = computed(() => ({
// 根据不同条件应用不同的激活样式类名
[getLinkClass(props.activeClass, options.linkActiveClass, 'router-link-active')]: link.isActive,
// [getLinkClass(props.inactiveClass, options.linkInactiveClass, 'router-link-inactive')]: !link.isExactActive,
[getLinkClass(props.exactActiveClass, options.linkExactActiveClass, 'router-link-exact-active')]: link.isExactActive,
}))
// 5. 渲染函数:
// a. 获取默认插槽内容,并将link状态对象传递给子组件
const children = slots.default && slots.default(link)
// b. 根据props.custom的值判断如何渲染:
// - 如果custom为true,直接渲染子组件内容
// - 否则,将子组件内容包装在一个带有路由链接状态属性的<a>标签内
return () => {
if (props.custom) {
return children
} else {
return h(
'a',
{
// 添加aria-current属性以表明当前活动链接状态
'aria-current': link.isExactActive ? props.ariaCurrentValue : null,
// 设置链接href属性
href: link.href,
// 添加点击事件监听器,用于导航至链接目标
onClick: link.navigate,
// 应用之前计算得到的类名对象
class: elClass.value,
},
children
)
}
}
}
router-link的ts接口定义为RouterLinkProps,也就是router-link的接收参数:
TS
export interface RouterLinkOptions {
to: RouteLocationRaw
replace?: boolean
}
export interface RouterLinkProps extends RouterLinkOptions {
custom?: boolean
activeClass?: string
exactActiveClass?: string
ariaCurrentValue?:
| 'page'
| 'step'
| 'location'
| 'date'
| 'time'
| 'true'
| 'false'
}
- to:跳转的路由链接,接收字符串或者路由对象,使用对象时候我们可以传参。
js
<router-link to="my-page"></router-link>
<router-link to="{name:'my-page',params:{a:'1'}}"></router-link>
具体的ts类型为RouteLocationRaw。
- replace:是否替换路由,接收布尔值,如果为false,那么点击跳转就会是router.replace。
- activeClass:点击后的样式,类似于a标签点击后的伪类选择器。
- exactActiveClass:点击后的样式,跟acitveClass不同,它是需要严格匹配路由才会触发。
- custom:是否使用自定义链接,设置为true时,配合着v-slot使用,通过v-slot获取参数,在自定义的链接中使用。
router-view
router-view:用来显示组件,在vue中一个路由会有着对应的vue文件,如果只使用router-link跳转路由,而没有使用router-view那么页面就会是空白的,router-view就像窗口将路由对应的组件展示出来啦。 router-view的参数很简单:
- name:组件名称,渲染出名称对应的页面。
- route:路由对象。
js
export interface RouterViewProps {
name?: string
route?: RouteLocationNormalized
}
router-view是用来渲染视图的组件,外面可以包裹transition做动画过渡效果,也可以用keep-alive缓存组件。