123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- <template>
- <div class="floating">
- <div>
- <Logo :show-logo="!isCollapse"/>
- <div style="height: 30px; padding: 0 8px 8px 8px" @click="expandMenu" id="tutorial_search_menu">
- <el-input
- ref="searchRef"
- v-model="menuText"
- prefix-icon="Search"
- clearable
- @input="searchInput"
- placeholder="菜单太难找?在这里搜索。"/>
- </div>
- </div>
- <div class="layout_flex_1-y">
- <el-scrollbar>
- <el-menu
- ref="menuRef"
- :collapse-transition="false"
- :collapse="isCollapse"
- :default-active="isSearch ? '' : activeMenu"
- :unique-opened="isSearch ? false : expandOneMenu">
- <template v-for="item in isSearch ? searchData : menuData">
- <menu-item-v2
- :data="item"
- v-if="item?.metaShowMenu"
- :menuText="menuText"/>
- </template>
- </el-menu>
- </el-scrollbar>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import MenuItemV2 from "./MenuItemV2.vue";
- import {computed, nextTick, onMounted, Ref, ref, watch} from "vue";
- import {useRoute} from "vue-router";
- import Logo from '../HeaderV2/Logo.vue'
- import XEUtils from "xe-utils";
- import router, {routerMenus} from '@/router'
- import sleep from "@/utils/sleep";
- import {treeSearch} from "@/utils/array-utils";
- import {useCompRef} from "@/utils/useCompRef";
- import {ElMenu} from "element-plus";
- import {useSystemStore} from "@/pinia/system-store";
- import {stringNotBlank} from "@/utils/blank-utils";
- const menuText: Ref<string> = ref('')
- const menuRef = useCompRef(ElMenu)
- const menuData = computed(() => {
- return routerMenus.value
- })
- const isSearch = ref<boolean>(false)
- const searchData = ref([])
- const searchActives = new Set()
- const searchInput: (val: string) => void = XEUtils.debounce(async (val: string) => {
- menuText.value = val;
- searchActives.clear();
- if (val) {
- searchData.value = treeSearch<{ metaTitle: string; }>(menuData.value, (item) => {
- const metaTitle: string = item.metaTitle
- if (stringNotBlank(metaTitle)) {
- return metaTitle.includes(val);
- }
- return false
- });
- isSearch.value = true
- await nextTick()
- expandNodes(searchData.value)
- } else {
- searchData.value = []
- await nextTick()
- isSearch.value = false
- smoothScrolling()
- }
- }, 500)
- const expandNodes = (treeData) => {
- const traverse = tempData => {
- XEUtils.arrayEach(tempData, (item) => {
- if (item.children !== null && item.children.length > 0) {
- menuLaunch(item.name)
- traverse(item.children);
- }
- })
- }
- traverse(treeData)
- }
- const menuLaunch = async path => {
- await nextTick();
- const li = document.getElementById(path);
- const div = li.children[0];
- const icon = div.getElementsByClassName('el-icon el-sub-menu__icon-arrow');
- // @ts-ignore
- if (icon.item(0).style.transform === 'none') {
- try {
- // @ts-ignore
- div!.click();
- } catch (e) {
- }
- }
- }
- const systemStore = useSystemStore()
- const expandOneMenu = computed<boolean>(() => systemStore.expandOneMenu)
- const route = useRoute()
- const isCollapse = computed<boolean>(() => systemStore.getCollapse)
- const expandMenu = () => {
- if (isCollapse.value) {
- systemStore.setCollapse(false)
- setTimeout(() => {
- searchRef.value!.focus()
- }, 100)
- }
- }
- const searchRef: Ref<HTMLHeadElement | null> = ref(null)
- const activeMenu = computed<string>(() => {
- const {meta, path} = route
- if (meta['activeMenu']) {
- return meta['activeMenu'] as string
- }
- return path
- })
- const smoothScrolling = () => {
- const routerPath = document.getElementById(<string>router.currentRoute.value.name)
- if (!routerPath) return
- routerPath.scrollIntoView({
- block: 'center',
- inline: 'nearest',
- behavior: 'smooth'
- })
- }
- watch(() => router.currentRoute.value, async () => {
- menuText.value = ''
- isSearch.value = false
- await nextTick()
- await sleep(200)
- smoothScrolling()
- })
- onMounted(async () => {
- await nextTick()
- await sleep(500)
- smoothScrolling()
- })
- </script>
- <style scoped lang="scss">
- .floating {
- height: 100%;
- width: 100%;
- background-color: var(--el-menu-bg-color);
- display: flex;
- flex-direction: column;
- .el-menu {
- border-right: 0 !important;
- position: relative;
- }
- .menu {
- overflow: auto;
- }
- }
- :deep(.el-sub-menu__title) {
- padding: 0 16px;
- }
- </style>
|