router-link
在 Vue Router 中,<router-link>
组件用于创建导航链接。它有多个属性,其中 path
和 query
属性用于指定导航目标和传递查询参数。
<router-link>
的 to
属性
<router-link>
使用 to
属性来定义导航目标。to
属性可以是一个字符串或一个对象。
字符串形式
当 to
是一个字符串时,它代表路径:
1
|
<router-link to="/about">About</router-link>
|
对象形式
当 to
是一个对象时,你可以指定路径和查询参数等:
1
|
<router-link :to="{ path: '/about', query: { plan: 'premium' } }">About</router-link>
|
path
和 query
属性详解
path
属性
path
属性指定导航的目标路径。例如:
1
|
<router-link :to="{ path: '/about' }">About</router-link>
|
query
属性
query
属性用于指定查询参数,它是一个对象。例如:
1
|
<router-link :to="{ path: '/about', query: { plan: 'premium' } }">About</router-link>
|
在这个例子中,生成的 URL 会是 /about?plan=premium
。
示例
综合使用 path
和 query
属性:
1
2
3
4
5
|
<template>
<div>
<router-link :to="{ path: '/user', query: { id: 123, name: 'John' } }">User Profile</router-link>
</div>
</template>
|
这个链接会导航到 /user?id=123&name=John
。
完整示例
下面是一个完整的 Vue 组件示例,展示如何使用 path
和 query
属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<template>
<div>
<h1>Navigation Links</h1>
<router-link to="/">Home</router-link>
<router-link :to="{ path: '/about' }">About</router-link>
<router-link :to="{ path: '/contact', query: { ref: 'newsletter' } }">Contact</router-link>
<router-link :to="{ path: '/profile', query: { user: 'john', age: 30 } }">Profile</router-link>
</div>
</template>
<script>
export default {
name: 'App'
};
</script>
|
总结
- 使用
to
属性来定义导航目标,可以是字符串或对象。
- 使用
path
属性指定目标路径。
- 使用
query
属性传递查询参数。
通过这些属性,你可以轻松地创建动态导航链接,满足各种导航需求。
自定义router-link
通过自定义 router-link
组件,可以实现更多样化的样式和行为控制。你展示的代码片段使用了 custom
属性来定义一个插槽,并手动处理导航行为和样式。
解释代码片段
v-bind="$props"
: 传递所有 props
给 router-link
。
custom
: 启用 custom
模式,使得 router-link
不会自动生成一个 <a>
标签,而是允许你自定义内容。
v-slot="{ isActive, href, navigate }"
: 使用插槽属性接收 isActive
(是否处于激活状态)、href
(目标链接)和 navigate
(导航函数)。
完整示例
结合你的代码片段,以下是如何将其集成到组件中的完整示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
<template>
<el-sub-menu v-if="item.children && item.children.length > 0" :index="String(item.id)">
<template #title>
<Icon :icon="item.meta.icon" />
<span>{{ item.meta.title }}</span>
</template>
<my-menu-item v-for="citem in item.children" :item="citem" :key="citem.id"></my-menu-item>
</el-sub-menu>
<router-link
v-else
v-bind="$props"
custom
v-slot="{ isActive, href, navigate }"
>
<a
v-bind="$attrs"
:href="href"
@click="navigate"
:class="isActive ? activeClass : inactiveClass"
>
<el-menu-item :index="String(item.id)">
<template #title>
<Icon :icon="item.meta.icon" />
<span>{{ item.meta.title }}</span>
</template>
</el-menu-item>
</a>
</router-link>
</template>
<script setup lang="ts">
import { MenuItem } from "@/types/component/menuItem";
import { Icon } from '@iconify/vue';
// 使用 defineOptions 关闭 inheritAttrs
defineOptions({
inheritAttrs: false,
});
// 定义 props
const props = defineProps<{
item: MenuItem;
}>();
const to = computed(() => {
return props.item.path ? { path: props.item.path } : null;
});
// 定义类名
const activeClass = 'menu-item-active';
const inactiveClass = 'menu-item-inactive';
</script>
<style>
.no-underline {
text-decoration: none;
}
.menu-item-active {
/* 添加激活状态的样式 */
}
.menu-item-inactive {
/* 添加非激活状态的样式 */
}
</style>
|
解释
- 自定义
router-link
: 使用 custom
模式和插槽属性 isActive
, href
, navigate
自定义内容。
- 样式处理: 使用
activeClass
和 inactiveClass
定义激活和非激活状态的样式类。
v-bind="$props"
和 v-bind="$attrs"
: 分别将所有 props
和 attrs
传递给 router-link
和 <a>
标签。
navigate
方法: 确保点击事件正确触发导航。
这种方法允许你完全控制导航行为和样式,同时确保链接行为与 Vue Router 的一致性。
扩展router-link的props并支持类型限定
为了在使用 TypeScript 时为 ...RouterLink.props
添加类型限定,你需要在 defineProps
中明确指定属性的类型。可以通过创建一个类型定义并将其与 RouterLink
的属性结合使用来实现。
实现步骤
- 导入
RouterLink
的属性类型。
- 定义一个包含你希望扩展的属性类型的接口。
- 结合
RouterLink
的属性类型与自定义属性类型。
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<script setup lang="ts">
import { RouterLink, RouterLinkProps } from 'vue-router';
import { defineProps } from 'vue';
// 定义一个包含 RouterLink 属性和自定义属性的类型
interface CustomRouterLinkProps extends RouterLinkProps {
inactiveClass?: string;
}
// 使用 TypeScript 定义属性
const props = defineProps<CustomRouterLinkProps>();
// 计算属性等逻辑
const to = computed(() => {
return props.to ? { path: props.to as string } : null;
});
const activeClass = 'menu-item-active';
const inactiveClass = props.inactiveClass || 'menu-item-inactive';
</script>
|
解释
-
导入类型:
1
|
import { RouterLink, RouterLinkProps } from 'vue-router';
|
-
定义接口:
1
2
3
|
interface CustomRouterLinkProps extends RouterLinkProps {
inactiveClass?: string;
}
|
-
在 defineProps
中使用自定义类型:
1
|
const props = defineProps<CustomRouterLinkProps>();
|
完整示例
结合你的代码结构,以下是完整的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
<template>
<el-sub-menu v-if="item.children && item.children.length > 0" :index="String(item.id)">
<template #title>
<Icon :icon="item.meta.icon" />
<span>{{ item.meta.title }}</span>
</template>
<my-menu-item v-for="citem in item.children" :item="citem" :key="citem.id"></my-menu-item>
</el-sub-menu>
<router-link
v-else
v-bind="$props"
custom
v-slot="{ isActive, href, navigate }"
>
<a
v-bind="$attrs"
:href="href"
@click="navigate"
:class="isActive ? activeClass : inactiveClass"
>
<el-menu-item :index="String(item.id)">
<template #title>
<Icon :icon="item.meta.icon" />
<span>{{ item.meta.title }}</span>
</template>
</el-menu-item>
</a>
</router-link>
</template>
<script setup lang="ts">
import { RouterLink, RouterLinkProps } from 'vue-router';
import { defineProps } from 'vue';
import { MenuItem } from "@/types/component/menuItem";
import { Icon } from '@iconify/vue';
// 使用 defineOptions 关闭 inheritAttrs
defineOptions({
inheritAttrs: false,
});
// 定义一个包含 RouterLink 属性和自定义属性的类型
interface CustomRouterLinkProps extends RouterLinkProps {
inactiveClass?: string;
}
// 使用 TypeScript 定义属性
const props = defineProps<CustomRouterLinkProps>();
// 计算属性等逻辑
const to = computed(() => {
return props.to ? { path: props.to as string } : null;
});
const activeClass = 'menu-item-active';
const inactiveClass = props.inactiveClass || 'menu-item-inactive';
</script>
<style>
.no-underline {
text-decoration: none;
}
.menu-item-active {
/* 添加激活状态的样式 */
}
.menu-item-inactive {
/* 添加非激活状态的样式 */
}
</style>
|
总结
通过导入 RouterLink
的属性类型并创建一个自定义类型接口,你可以在 defineProps
中为扩展属性添加类型限定。这种方法确保了代码的类型安全性和可维护性。
router-link的v-slot
属性接收的数据
在 Vue Router 中,<router-link>
组件使用 v-slot
提供了一些插槽属性,这些属性包含了关于链接状态和导航的有用信息。具体来说,当你使用 custom
属性时,<router-link>
组件会向插槽传递一个对象,该对象包含 isActive
, href
, 和 navigate
等属性。
这些属性的数据来源如下:
isActive
: 一个布尔值,指示当前链接是否处于激活状态(即,当前路由是否与该链接匹配)。
href
: 生成的链接 URL,基于传递给 to
属性的目标路径。
navigate
: 一个方法,用于执行导航操作,当用户点击链接时调用此方法来进行路由导航。
数据传递的过程
当你在 <router-link>
组件中使用 v-slot
和 custom
属性时,<router-link>
会传递这些插槽属性给你定义的内容。这是 Vue Router 内部实现的一部分,确保你可以完全自定义链接的渲染方式,同时保留路由导航功能。
代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
<template>
<router-link
v-else
v-bind="$props"
custom
v-slot="{ isActive, href, navigate }"
>
<a
v-bind="$attrs"
:href="href"
@click="navigate"
:class="isActive ? activeClass : inactiveClass"
>
<el-menu-item :index="String(item.id)">
<template #title>
<Icon :icon="item.meta.icon" />
<span>{{ item.meta.title }}</span>
</template>
</el-menu-item>
</a>
</router-link>
</template>
<script setup lang="ts">
import { RouterLink, RouterLinkProps } from 'vue-router';
import { defineProps } from 'vue';
import { MenuItem } from "@/types/component/menuItem";
import { Icon } from '@iconify/vue';
// 使用 defineOptions 关闭 inheritAttrs
defineOptions({
inheritAttrs: false,
});
// 定义一个包含 RouterLink 属性和自定义属性的类型
interface CustomRouterLinkProps extends RouterLinkProps {
inactiveClass?: string;
}
// 使用 TypeScript 定义属性
const props = defineProps<CustomRouterLinkProps>();
// 计算属性等逻辑
const to = computed(() => {
return props.to ? { path: props.to as string } : null;
});
const activeClass = 'menu-item-active';
const inactiveClass = props.inactiveClass || 'menu-item-inactive';
</script>
<style>
.no-underline {
text-decoration: none;
}
.menu-item-active {
/* 添加激活状态的样式 */
}
.menu-item-inactive {
/* 添加非激活状态的样式 */
}
</style>
|
在这个示例中,<router-link>
使用 custom
属性并定义了一个插槽,该插槽接收三个属性:
isActive
: 当前链接是否处于激活状态。
href
: 生成的链接 URL。
navigate
: 一个方法,用于执行导航。
这些属性是由 Vue Router 的 <router-link>
组件内部传递的。使用这些属性,你可以完全自定义链接的外观和行为,同时确保路由导航功能正常工作。
总结
通过 v-slot="{ isActive, href, navigate }"
,你可以从 Vue Router 的 <router-link>
组件中获取到关于链接状态和导航功能的上下文数据。Vue Router 通过 custom
模式提供这些数据,以便你可以灵活地自定义链接的渲染和交互行为。