feat: 🎸 新增固定一级菜单配置

This commit is contained in:
陈凯龙
2021-03-29 17:40:04 +08:00
parent 62eeb55330
commit 4c4903e806
25 changed files with 362 additions and 59 deletions

View File

@@ -1,96 +0,0 @@
<template>
<div ref="breadcrumbRef" class="breadcrumb">
<slot />
</div>
</template>
<script lang="ts">
import type { PropType } from 'vue'
import { defineComponent, provide, ref } from 'vue'
export default defineComponent({
name: 'Breadcrumb',
props: {
separator: {
type: String as PropType<string>,
default: '/'
},
separatorClass: {
type: String as PropType<string>,
default: ''
}
},
setup(props) {
const breadcrumbRef = ref<HTMLElement | null>(null)
provide('breadcrumb', props)
return {
breadcrumbRef
}
}
})
</script>
<style lang="less">
.breadcrumb {
padding-right: 20px;
font-size: 12px;
&::after,
&::before {
display: table;
content: '';
}
&::after {
clear: both;
}
&__separator {
margin: 0 9px;
font-weight: 700;
color: #6e90a7;
&[class*='icon'] {
margin: 0 6px;
font-weight: 400;
}
}
&__item {
float: left;
display: inline-block;
}
&__inner {
display: inline-block;
color: #6e90a7;
a {
font-weight: 700;
color: #2c3a61;
text-decoration: none;
transition: color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
}
a:hover,
&.is-link:hover {
color: #1890ff;
cursor: pointer;
}
}
&__item:last-child .breadcrumb__inner,
&__item:last-child &__inner a,
&__item:last-child &__inner a:hover,
&__item:last-child &__inner:hover {
font-weight: 400;
color: #6e90a7;
cursor: text;
}
&__item:last-child &__separator {
display: none;
}
}
</style>

View File

@@ -1,51 +0,0 @@
<template>
<span class="breadcrumb__item">
<span ref="linkRef" :class="['breadcrumb__inner']">
<slot />
</span>
<i v-if="separatorClass" class="breadcrumb__separator" :class="separatorClass" />
<span v-else class="breadcrumb__separator">{{ separator }}</span>
</span>
</template>
<script lang="ts">
import { defineComponent, inject, ref, onMounted, unref } from 'vue'
import type { PropType } from 'vue'
import { useRouter } from 'vue-router'
export default defineComponent({
name: 'BreadcrumbItem',
props: {
to: {
type: [String, Object] as PropType<string | object>,
default: ''
},
replace: {
type: Boolean as PropType<boolean>,
default: false
}
},
setup(props) {
const linkRef = ref<HTMLElement | null>(null)
const parent = inject('breadcrumb') as {
separator: string
separatorClass: string
}
const { push, replace } = useRouter()
onMounted(() => {
const link = unref(linkRef)
if (!link) return
const { to } = props
if (!props.to) return
props.replace ? replace(to) : push(to)
})
return {
linkRef,
separator: parent.separator && parent.separator,
separatorClass: parent.separatorClass && parent.separatorClass
}
}
})
</script>

View File

@@ -1,107 +0,0 @@
<template>
<Breadcrumb class="app-breadcrumb">
<transition-group name="breadcrumb">
<BreadcrumbItem
v-for="(item,index) in levelList"
:key="item.path"
>
<svg-icon v-if="item.meta.icon" :icon-class="item.meta.icon" class="icon-breadcrumb" />
<span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">
{{ item.meta.title }}
</span>
<a v-else @click.prevent="handleLink(item)">
{{ item.meta.title }}
</a>
</BreadcrumbItem>
</transition-group>
</Breadcrumb>
</template>
<script lang="ts">
import { ref, defineComponent, watch } from 'vue'
import type { RouteRecordRaw, RouteLocationMatched, RouteLocationNormalizedLoaded } from 'vue-router'
import { useRouter } from 'vue-router'
import { compile } from 'path-to-regexp'
import Breadcrumb from './Breadcrumb.vue'
import BreadcrumbItem from './BreadcrumbItem.vue'
export default defineComponent({
name: 'BreadcrumbWrap',
components: {
Breadcrumb,
BreadcrumbItem
},
setup() {
const { currentRoute, push } = useRouter()
const levelList = ref<RouteRecordRaw[]>([])
function getBreadcrumb() {
let matched: any[] = currentRoute.value.matched.filter((item: RouteLocationMatched) => item.meta && item.meta.title)
const first = matched[0]
if (!isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: '首页', icon: 'dashboard' }}].concat(matched)
}
levelList.value = matched.filter((item: RouteLocationMatched) => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}
function isDashboard(route: RouteLocationMatched) {
const name = route && route.name
if (!name) {
return false
}
return (name as any).trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
}
function pathCompile(path: string): string {
const { params } = currentRoute.value
const toPath = compile(path)
return toPath(params)
}
function handleLink(item: RouteRecordRaw): void {
const { redirect, path } = item
if (redirect) {
push(redirect as string)
return
}
push(pathCompile(path))
}
watch(
() => currentRoute.value,
(route: RouteLocationNormalizedLoaded) => {
if (route.path.startsWith('/redirect/')) {
return
}
getBreadcrumb()
},
{
immediate: true
}
)
return {
levelList,
handleLink
}
}
})
</script>
<style lang="less" scoped>
.app-breadcrumb {
display: inline-block;
font-size: 14px;
margin-left: 10px;
.no-redirect {
color: #97a8be;
cursor: text;
}
.icon-breadcrumb {
color: #97a8be;
margin-right: 8px;
}
}
</style>