通用管理后台组件库-12-面包屑导航组件

18 阅读1分钟

面包屑导航

说明:实现基础面包屑导航。

1.实现效果

image.png

2.面包屑组件

<template>
  <el-breadcrumb :separator-icon="ArrowRightIcon">
    <transition-group name="breadcrumb" @enter="onEnter" :css="false">
      <!-- transition-group自带过渡效果 -->
    <!-- <transition-group name="breadcrumb"> -->
      <el-breadcrumb-item
        :to="{ path: item.name }"
        v-for="(item, index) in breadcrumbData"
        :key="item.name"
        :data-index="index"
      >
        <span>{{ $t(item.meta?.title) }}</span>
      </el-breadcrumb-item>
    </transition-group>
  </el-breadcrumb>
</template>
<script setup lang="tsx">
import { ArrowRight } from '@element-plus/icons-vue'
import { TransitionGroup } from 'vue'
import { useRoute } from 'vue-router/auto'
import gsap from 'gsap'

const ArrowRightIcon = () => (
  <el-icon>
    <ArrowRight />
  </el-icon>
)

const route = useRoute()

const breadcrumbData = ref<any>([])
// 获取面包屑数据
function getBreadcrumbData() {
  breadcrumbData.value = route.matched.filter((item) => item.name && item.meta && item.meta?.title)
}

// 监听路由变化
watch(
  route,
  () => {
    getBreadcrumbData()
  },
  { immediate: true }
)

// 过渡动画库
function onEnter(el, done) {
  gsap.fromTo(
    el,
    {
      opacity: 0,
      x: 30
    },
    {
      opacity: 1,
      x: 0,
      delay: el.dataset.index * 0.15,
      onComplete: done
    }
  )
}

function onLeave(el, done) {
  gsap.to(el, {
    opacity: 0,
    height: 0,
    duration: 0.5,
    onComplete: done
  })
}
</script>

<style scoped lang="scss">
.breadcrumb-move,
.breadcrumb-enter-active,
.breadcrumb-leave-active {
  transition: all 0.5s;
}
.breadcrumb-enter-from,
.breadcrumb-leave-to {
  opacity: 0;
  transform: translateX(20px);
}
.breadcrumb-leave-active {
  position: absolute;
}
</style>

3.布局的Header.vue中引用

<template>
  <el-row class="flex items-center flex-nowrap! h-[50px]">
    <!-- 折叠图标 -->
    <Icon
      :icon="collapseModel ? 'ep:expand' : 'ep:fold'"
      @click="collapseModel = !collapseModel"
      class="cursor-pointer text-2xl ml-2"
      v-if="setting?.mode !== 'top'"
    />
    <Breadcrumb class="ml-4" v-if="!['mix', 'top'].includes(setting?.mode || '')"></Breadcrumb>
    <div class="flex-grow relative overflow-x-hidden">
      <slot name="menu"></slot>
    </div>
    <el-row class="flex items-center flex-nowrap!">
      <!-- 设置主题 -->
      <ThemeSettings class="mr-3" @change="handleChange" v-bind="setting"></ThemeSettings>
      <!-- 暗黑模式 -->
      <DarkModeTaggle
        class="mr-3"
        :dark="setting?.darkMode"
        @change="handleChangeDarkMode"
      ></DarkModeTaggle>
      <!-- 国际化 -->
      <ChangeLocale :locales="locales" class="mr-2" @change="changeLocale"></ChangeLocale>
      <!-- 全屏 -->
      <FullScreen class="mr-2"></FullScreen>
      <el-divider direction="vertical"></el-divider>
      <!-- 用户信息 -->
      <Avatar
        v-if="username || src"
        v-bind="avatarProps"
        @command="handleCommand"
        class="mx-2"
      ></Avatar>
    </el-row>
  </el-row>
</template>

<script setup lang="ts">
import { Icon } from '@iconify/vue'
import type { ThemeSettingProps } from '../Themes/type'
import type { HeaderProps } from './types'
import { loadLocaleMessages } from '@/modules/i18n'
import Breadcrumb from '../Themes/Breadcrumb.vue'

const props = withDefaults(defineProps<HeaderProps>(), {
  collapse: false
})

// 使用v-model指令父子组件双向绑定,实现抽屉的展开和收起
const collapseModel = defineModel('collapse', {
  type: Boolean,
  default: false
})

// 获取头部导航栏数据,实现暗黑模式和主题设置中的数据转换
const localProps = reactive({ ...props })

// 过滤出头像数据
const avatarProps = computed(() => {
  const { collapse, locales, ...restProps } = props
  return restProps
})

// 回传数据
const emits = defineEmits<{
  menuChange: [arg: string | number | object]
  settingChange: [settings: ThemeSettingProps]
}>()

// 监听主题设置中的变化
watch(
  () => localProps.setting,
  () => {
    emits('settingChange', localProps.setting!)
  },
  { deep: true }
)

const handleCommand = (command: string | number | object) => {
  emits('menuChange', command)
}
// 主题设置
const handleChange = (settings: ThemeSettingProps) => {
  localProps.setting = settings
}
// 暗黑模式切换
const handleChangeDarkMode = (darkMode: boolean) => {
  localProps.setting!.darkMode = darkMode
}
// 切换中英文
const changeLocale = (locale: string) => {
  loadLocaleMessages(locale)
}
</script>

<style scoped></style>