router-link的custom模式
vue项目vue-router中的router-link路由负责管理页面的呈现,今天介绍router-link的custom模式。
什么是 custom模式?
custom 是 router-link 的高级配置属性,启用后会:
- 取消默认a标签渲染,允许开发者使用任意 DOM 元素(如
<button>、<div>、<li>等)作为导航容器; - 通过插槽(
v-slot)暴露路由核心状态(激活状态、跳转方法),让开发者手动控制导航逻辑; - 保留 Vue Router 原生功能(如无刷新跳转、路由守卫触发、历史记录管理)。
简单来说,custom 模式允许自定义,让导航组件既符合设计需求,又不丢失路由特性。
插槽暴露的关键属性
启用 custom 模式后,router-link 会通过作用域插槽暴露 4 个核心属性,这是实现自定义导航的基础:
| 属性名 | 类型 | 说明 |
|---|---|---|
navigate |
函数 | 手动触发路由跳转(替代默认 <a> 标签的点击行为,支持无刷新跳转) |
isActive |
布尔值 | 模糊匹配激活:目标路径是当前路径的子集时为 true(例:/user 匹配 /user/123) |
isExactActive |
布尔值 | 精确匹配激活:目标路径与当前路径完全一致时为 true(例:/user 仅匹配 /user) |
href |
字符串 | 生成的完整 URL(如 /home 对应 #/home,可用于自定义元素的 href 属性) |
navigate 负责跳转逻辑,isActive/isExactActive 控制激活状态,两者结合就能实现完全自定义的导航组件。
基础用法
语法结构
vue
<router-link
to="/target-path" <!-- 跳转目标(与普通 router-link 一致) -->
custom <!-- 启用自定义模式 -->
v-slot="{ isActive, isExactActive, navigate }" <!-- 解构插槽属性 -->
>
<!-- 自定义导航元素(任意 DOM 结构) -->
<div
class="custom-link"
:class="{
'active': isActive, // 模糊匹配激活样式
'exact-active': isExactActive // 精确匹配激活样式
}"
@click="navigate" <!-- 手动绑定跳转事件 -->
>
自定义导航
</div>
</router-link>
关键说明
- 必须手动通过
@click="navigate"触发跳转,否则点击元素不会生效; - 激活样式需通过
isActive/isExactActive手动绑定,默认active-class属性失效; - 支持
replace、append等普通router-link支持的属性(例:replace跳转不添加历史记录)。
官方的AppLink组件写法
html
<script setup>
import { computed } from 'vue'
import { RouterLink } from 'vue-router'
defineOptions({
inheritAttrs: false,
})
const props = defineProps({
// 如果使用 TypeScript,请添加 @ts-ignore
...RouterLink.props,
inactiveClass: String,
})
const isExternalLink = computed(() => {
return typeof props.to === 'string' && props.to.startsWith('http')
})
</script>
<template>
<a v-if="isExternalLink" v-bind="$attrs" :href="to" target="_blank">
<slot />
</a>
<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"
>
<slot />
</a>
</router-link>
</template>
封装后优势:一个 组件搞定所有导航需求:
传入 to="http://xxx"(外部链接):自动渲染原生 <a> 标签,带 target="_blank" 新窗口打开;
传入 to="/about"(内部路由):自动用 router-link 实现无刷新跳转;
统一使用 ,降低代码冗余。
小问题
是否可以将router-link包含在a标签内?
不可以
<a>是原生导航标签,点击会触发浏览器默认跳转(刷新页面或跳转到新 URL);
是 Vue Router 封装的路由导航组件,核心作用是「无刷新跳转内部路由」。
两者嵌套后,点击时会同时触发<a>的原生跳转和 的路由跳转,导致跳转行为混乱(可能刷新页面,失去 Vue Router 的无刷新优势)。
DOM 结构不合理:- 原生 HTML 中,
<a>标签是「内联元素」,且不建议嵌套其他可交互元素(尤其是另一个导航元素);
本质是组件,渲染后会生成 DOM 元素(默认是<a>,custom 模式下是自定义元素),嵌套后会出现「<a>包含<a>」的非法 DOM 结构(浏览器会自动修正,导致样式 / 行为异常)。