可自定义设置以下属性:
router 的路由数组(routes),类型:Array<{name: string, path?: string, query?: { [propName: string]: any } }>,默认 []
设置面包屑类名(breadcrumbClass),类型:string,默认 undefined
设置面包屑样式(breadcrumbStyle),类型:CSSProperties,默认 {}
设置文本最大显示宽度,超出后显示省略号(maxWidth),类型:string | number,单位 px,默认 '100%'
自定义分隔符(separator),类型:string | slot,默认 undefined,默认使用 > 分隔
设置分隔符样式(separatorStyle),类型:CSSProperties,默认 {}
如何打开目标URL,当前窗口或新窗口(target),类型:'_self' | '_blank',默认 '_self'
效果如下图:在线预览
①创建面包屑组件Breadcrumb.vue:
<script setup lang="ts">
import { computed } from 'vue'
import type { CSSProperties } from 'vue'
interface Query {
[propName: string]: any // 添加一个字符串索引签名,用于包含带有任意数量的其他属性
}
interface Route {
name: string // 路由名称
path?: string // 路由地址
query?: Query // 路由查询参数
}
interface Props {
routes?: Route[] // router 路由数组
breadcrumbClass?: string // 设置面包屑类名
breadcrumbStyle?: CSSProperties // 设置面包屑样式
maxWidth?: string | number // 设置文本最大显示宽度,超出后显示省略号,单位 px
separator?: string // 自定义分隔符,默认为 > string | slot
separatorStyle?: CSSProperties // 设置分隔符样式
target?: '_self' | '_blank' // 如何打开目标 URL,当前窗口或新窗口
}
const props = withDefaults(defineProps<Props>(), {
routes: () => [],
breadcrumbClass: undefined,
breadcrumbStyle: () => ({}),
maxWidth: '100%',
separator: undefined,
separatorStyle: () => ({}),
target: '_self'
})
const len = computed(() => {
return props.routes.length
})
function getUrl(route: Route) {
var targetUrl = route.path
if (route.query && JSON.stringify(route.query) !== '{}') {
const query = route.query
Object.keys(query).forEach((param, index) => {
if (index === 0) {
targetUrl = targetUrl + '?' + param + '=' + query[param]
} else {
targetUrl = targetUrl + '&' + param + '=' + query[param]
}
})
}
return targetUrl
}
</script>
<template>
<div class="m-breadcrumb" :class="breadcrumbClass" :style="breadcrumbStyle">
<div class="m-breadcrumb-item" v-for="(route, index) in routes" :key="index">
<a
v-if="route.path"
class="breadcrumb-link link-hover"
:class="{ 'link-active': index === len - 1 }"
:style="`max-width: ${maxWidth}px;`"
:href="getUrl(route)"
:target="target"
:title="route.name"
>
{
{ route.name }}
</a>
<span
v-else
class="breadcrumb-link"
:class="{ 'link-active': index === len - 1 }"
:style="`max-width: ${maxWidth}px;`"
:title="route.name"
>
{
{ route.name }}
</span>
<span v-if="index < len - 1" class="breadcrumb-separator" :style="separatorStyle">
<slot name="separator" :index="index">
<span v-if="separator">{
{ separator }}</span>
<svg v-else class="icon-arrow" viewBox="64 64 896 896" data-icon="right" aria-hidden="true" focusable="false">
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z"
></path>
</svg>
</slot>
</span>
</div>
</div>
</template>
<style lang="less" scoped>
.m-breadcrumb {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1.5714285714285714;
display: flex;
align-items: center;
flex-wrap: wrap;
.m-breadcrumb-item {
display: inline-flex;
align-items: center;
.breadcrumb-link {
display: inline-block;
color: rgba(0, 0, 0, 0.45);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding: 0 4px;
border-radius: 4px;
text-decoration: none;
cursor: text;
transition:
color 0.2s,
background-color 0.2s;
}
.link-hover {
cursor: pointer;
&:hover {
background-color: rgba(0, 0, 0, 0.06);
color: rgba(0, 0, 0, 0.88);
}
}
.link-active {
color: rgba(0, 0, 0, 0.88);
}
.breadcrumb-separator {
display: inline-flex;
align-items: center;
margin: 0 4px;
color: rgba(0, 0, 0, 0.45);
:deep(svg) {
margin-inline: -2px;
}
.icon-arrow {
display: inline-block;
width: 1em;
height: 1em;
fill: rgba(0, 0, 0, 0.45);
}
}
}
}
</style>
②在要使用的页面引入:
<script setup lang="ts">
import Breadcrumb from './Breadcrumb.vue'
import { ref } from 'vue'
const routes = ref([
{
name: '一级路由',
path: '/first'
},
{
name: '二级路由',
path: '/second',
query: { id: 1, tab: 2 }
},
{
name: '三级路由'
}
])
const longNameRoutes = ref([
{
name: '一级路由'
},
{
name: '二级路由',
path: '/second',
query: { id: 1, tab: 2 }
},
{
name: '我是一个名字超长的三级路由'
}
])
</script>
<template>
<div>
<h1>{
{ $route.name }} {
{ $route.meta.title }}</h1>
<h2 class="mt30 mb10">基本使用</h2>
<Breadcrumb :routes="routes" />
<h2 class="mt30 mb10">自定义分隔符</h2>
<Flex vertical>
<Breadcrumb :routes="routes" separator="/" />
<Breadcrumb :routes="routes">
<template #separator>
<svg
class="svg-icon"
focusable="false"
data-icon="arrow-right"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
viewBox="64 64 896 896"
>
<path
d="M869 487.8L491.2 159.9c-2.9-2.5-6.6-3.9-10.5-3.9h-88.5c-7.4 0-10.8 9.2-5.2 14l350.2 304H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h585.1L386.9 854c-5.6 4.9-2.2 14 5.2 14h91.5c1.9 0 3.8-.7 5.2-2L869 536.2a32.07 32.07 0 000-48.4z"
></path>
</svg>
</template>
</Breadcrumb>
<Breadcrumb :routes="routes">
<template #separator>
<svg
class="svg-icon"
focusable="false"
data-icon="double-right"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
viewBox="64 64 896 896"
>
<path
d="M533.2 492.3L277.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H188c-6.7 0-10.4 7.7-6.3 12.9L447.1 512 181.7 851.1A7.98 7.98 0 00188 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5zm304 0L581.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H492c-6.7 0-10.4 7.7-6.3 12.9L751.1 512 485.7 851.1A7.98 7.98 0 00492 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5z"
></path>
</svg>
</template>
</Breadcrumb>
</Flex>
<h2 class="mt30 mb10">自定义样式</h2>
<Flex vertical>
<Breadcrumb
:routes="longNameRoutes"
breadcrumb-class="custom-breadcrumb-class"
:max-width="210" />
<Breadcrumb
:routes="longNameRoutes"
:breadcrumb-style="{ fontSize: '20px', height: '40px' }"
:separator-style="{ fontSize: '18px' }"
:max-width="210" />
<Breadcrumb
:routes="longNameRoutes"
:breadcrumb-style="{ fontSize: '20px', height: '40px' }"
:separator-style="{ fontSize: '18px' }"
:max-width="210">
<template #separator>
<svg
class="svg-icon"
focusable="false"
data-icon="arrow-right"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
viewBox="64 64 896 896"
>
<path
d="M869 487.8L491.2 159.9c-2.9-2.5-6.6-3.9-10.5-3.9h-88.5c-7.4 0-10.8 9.2-5.2 14l350.2 304H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h585.1L386.9 854c-5.6 4.9-2.2 14 5.2 14h91.5c1.9 0 3.8-.7 5.2-2L869 536.2a32.07 32.07 0 000-48.4z"
></path>
</svg>
</template>
</Breadcrumb>
<Breadcrumb
:routes="longNameRoutes"
:breadcrumb-style="{ fontSize: '20px', height: '40px' }"
:separator-style="{ fontSize: '18px' }"
:max-width="210">
<template #separator="{ index }">
<svg
v-if="index === 0"
class="svg-icon"
focusable="false"
data-icon="arrow-right"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
viewBox="64 64 896 896"
>
<path
d="M869 487.8L491.2 159.9c-2.9-2.5-6.6-3.9-10.5-3.9h-88.5c-7.4 0-10.8 9.2-5.2 14l350.2 304H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h585.1L386.9 854c-5.6 4.9-2.2 14 5.2 14h91.5c1.9 0 3.8-.7 5.2-2L869 536.2a32.07 32.07 0 000-48.4z"
></path>
</svg>
<svg
v-if="index === 1"
class="svg-icon"
focusable="false"
data-icon="double-right"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
viewBox="64 64 896 896"
>
<path
d="M533.2 492.3L277.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H188c-6.7 0-10.4 7.7-6.3 12.9L447.1 512 181.7 851.1A7.98 7.98 0 00188 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5zm304 0L581.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H492c-6.7 0-10.4 7.7-6.3 12.9L751.1 512 485.7 851.1A7.98 7.98 0 00492 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5z"
></path>
</svg>
</template>
</Breadcrumb>
</Flex>
<h2 class="mt30 mb10">新页面打开目标链接</h2>
<Breadcrumb :routes="routes" target="_blank" />
</div>
</template>
<style lang="less" scoped>
.svg-icon {
fill: rgba(0, 0, 0, 0.45);
}
.custom-breadcrumb-class {
font-size: 20px;
color: #1677ff;
height: 40px;
:deep(.m-breadcrumb-item) {
.breadcrumb-link {
color: rgba(22, 119, 255, 0.72);
padding: 0 8px;
border-radius: 8px;
}
.link-hover {
&:hover {
color: #fff;
background: #4096ff;
}
}
.link-active {
color: #1677ff;
}
.breadcrumb-separator {
.icon-arrow {
fill: rgba(22, 119, 255, 0.72);
}
}
}
}
</style>