Router Link

在 Vue Router 中,<router-link> 组件用于创建导航链接。它有多个属性,其中 pathquery 属性用于指定导航目标和传递查询参数。

<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>

pathquery 属性详解

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

示例

综合使用 pathquery 属性:

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 组件示例,展示如何使用 pathquery 属性:

 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 组件,可以实现更多样化的样式和行为控制。你展示的代码片段使用了 custom 属性来定义一个插槽,并手动处理导航行为和样式。

解释代码片段

  • v-bind="$props": 传递所有 propsrouter-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>

解释

  1. 自定义 router-link: 使用 custom 模式和插槽属性 isActive, href, navigate 自定义内容。
  2. 样式处理: 使用 activeClassinactiveClass 定义激活和非激活状态的样式类。
  3. v-bind="$props"v-bind="$attrs": 分别将所有 propsattrs 传递给 router-link<a> 标签。
  4. navigate 方法: 确保点击事件正确触发导航。

这种方法允许你完全控制导航行为和样式,同时确保链接行为与 Vue Router 的一致性。

扩展router-link的props并支持类型限定

为了在使用 TypeScript 时为 ...RouterLink.props 添加类型限定,你需要在 defineProps 中明确指定属性的类型。可以通过创建一个类型定义并将其与 RouterLink 的属性结合使用来实现。

实现步骤

  1. 导入 RouterLink 的属性类型
  2. 定义一个包含你希望扩展的属性类型的接口
  3. 结合 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. 导入类型:

    1
    
    import { RouterLink, RouterLinkProps } from 'vue-router';
    
  2. 定义接口:

    1
    2
    3
    
    interface CustomRouterLinkProps extends RouterLinkProps {
      inactiveClass?: string;
    }
    
  3. 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 等属性。

这些属性的数据来源如下:

  1. isActive: 一个布尔值,指示当前链接是否处于激活状态(即,当前路由是否与该链接匹配)。
  2. href: 生成的链接 URL,基于传递给 to 属性的目标路径。
  3. navigate: 一个方法,用于执行导航操作,当用户点击链接时调用此方法来进行路由导航。

数据传递的过程

当你在 <router-link> 组件中使用 v-slotcustom 属性时,<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 模式提供这些数据,以便你可以灵活地自定义链接的渲染和交互行为。

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计