Skip to content

Commit

Permalink
feat: 添加菜单搜索功能
Browse files Browse the repository at this point in the history
  • Loading branch information
yuntian001 committed Nov 9, 2022
1 parent 7a141c6 commit f42271c
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/components/meLocaleSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const setLanguage = (locale: string) => {
padding: 0 10px;
.icon {
font-size: 1.2em;
font-size: 1.3em;
}
}
}
Expand Down
89 changes: 89 additions & 0 deletions src/components/meSearchMenu/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<template>
<div class="me-search-menu pointer" @click="showSearch = true">
<mel-icon-search class="icon"></mel-icon-search>
<el-dialog
v-model="showSearch"
:show-close="false"
@keydown.down="handleDown() && srollToIndex()"
@keyup.up="handleUp() && srollToIndex()"
@keyup.enter="handleEnter();close();"
>
<div class="search">
<el-input
v-model="searchText"
size="large"
:placeholder="$t('搜索')+$t(' ')+$t('菜单')"
:prefix-icon="Search"
clearable
@input="search(searchText)"
>
</el-input>
<div v-if="filteredMenu.length" ref="listRef" class="list">
<el-scrollbar max-height="300px">
<a
v-for="(item, index) in filteredMenu"
:key="index"
class="item"
:class="{ active: activeIndex === index }"
@click.stop="jump(item);close()"
@mouseenter="activeIndex = index"
>
{{ item.meta.title }}
</a>
</el-scrollbar>
</div>
<el-empty v-else :image-size="80" />
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="MeSearchMenu">
import { useSearchMenu } from './useSearchMenu';
import { Search } from '@element-plus/icons-vue';
import { jump } from '@/router';
const showSearch = ref(false);
const searchText = ref('');
const listRef = ref<HTMLElement>();
const { filteredMenu, search, activeIndex, handleDown, handleUp, handleEnter } = useSearchMenu();
const srollToIndex = () => {
listRef.value!.querySelectorAll('.item')[activeIndex.value].scrollIntoView({
behavior: 'smooth',
});
};
const close = ()=>{
showSearch.value = false;
searchText.value = '';
filteredMenu.value = [];
}
</script>
<style lang="scss" scoped>
.me-search-menu {
padding: 0 10px;
display: flex;
align-items: center;
.icon {
font-size: 1.3em;
}
:deep(.el-dialog__header) {
display: none;
}
:deep(.el-dialog) {
min-width: 300px;
}
}
.search {
.list {
padding: 10px 0;
.item {
display: block;
padding: 10px 32px 10px 20px;
line-height: 1.2em;
}
.active {
color: var(--el-color-primary);
background-color: var(--el-fill-color-light);
}
}
}
</style>
86 changes: 86 additions & 0 deletions src/components/meSearchMenu/useSearchMenu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { useGlobalStore, useRouteStore } from '@/store';
import { RouteRecordRaw } from 'vue-router';
import { resolvePath, jump } from '@/router';

import { debounce } from 'lodash-es';
const menuList = [] as { path: string; isLink?: boolean; title: string[] }[];

const createMenuList = (routes: RouteRecordRaw[], baseTitle: string[] = [], basePath = '') => {
routes.forEach((item) => {
if (item.meta?.title) {
const path = resolvePath(item.path, basePath);
const title = [...baseTitle, item.meta.title];
if (!item.meta.hideMenu && (item.redirect || !item.children?.length)) {
menuList.push({
path,
title,
isLink: item.meta.isLink,
});
}
if (item.children) {
createMenuList(item.children, title, path);
}
}
});
};

export const useSearchMenu = (debounceTime = 500) => {
const { i18n } = useGlobalStore();
const { routes } = useRouteStore();
!menuList.length && createMenuList(routes);
const filteredMenu = ref<{ path: string; meta: { isLink?: boolean; title: string } }[]>([]);
const activeIndex = ref(0);
const search = debounce((searchText: string) => {
filteredMenu.value = [];
activeIndex.value = 0;
searchText && menuList.forEach((item) => {
const title = item.title.map((v) => i18n.t(v)).join(' > ');
if (title.search(searchText) > -1) {
filteredMenu.value.push({
path: item.path,
meta: {
title,
isLink: item.isLink,
},
});
}
return filteredMenu.value;
});
}, debounceTime);

// Arrow key up
function handleUp() {
if (!filteredMenu.value.length) return false;
activeIndex.value--;
if (activeIndex.value < 0) {
activeIndex.value = filteredMenu.value.length - 1;
}
return true;
}

// Arrow key down
function handleDown() {
if (!filteredMenu.value.length) return false;
activeIndex.value++;
if (activeIndex.value > filteredMenu.value.length - 1) {
activeIndex.value = 0;
}
return true;
}

// enter keyboard event
async function handleEnter() {
if (!filteredMenu.value[activeIndex.value]) return false;
jump(filteredMenu.value[activeIndex.value]);
return true;
}

return {
search,
filteredMenu,
activeIndex,
handleUp,
handleDown,
handleEnter
};
};
3 changes: 3 additions & 0 deletions src/components/meSettingMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<el-form-item :label="$t('顶栏')">
<el-switch v-model="themeConfig.topBar"></el-switch>
</el-form-item>
<el-form-item :label="$t('菜单') + $t(' ') + $t('搜索')">
<el-switch v-model="themeConfig.showSearchMenu"></el-switch>
</el-form-item>
<el-form-item :label="$t('模式') + $t(' ') + $t('切换')">
<el-switch v-model="themeConfig.showDark"></el-switch>
</el-form-item>
Expand Down
2 changes: 1 addition & 1 deletion src/components/meSizeSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const { themeConfig } = useSettingStore();
padding: 0 10px;
.icon {
font-size: 1.2em;
font-size: 1.3em;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/config/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export default {
tagBarMenu: true, // 标签栏快捷菜单
tagBarRefresh: true, // 标签栏刷新按钮
showSetting: true, // 展示设置按钮
showSearchMenu: true,//菜单搜索
};
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const isDot = ref(true);
.message-icon {
height: 25px;
line-height: 25px;
font-size: 1.2em;
font-size: 1.3em;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div class="right">
<div></div>
<me-search-menu v-if="themeConfig.showSearchMenu" class="item"></me-search-menu>
<me-dark-switch v-if="themeConfig.showDark" class="item no-hover"></me-dark-switch>
<me-locale-select v-if="localeConfig.localeList.length > 1" class="item"></me-locale-select>
<me-size-select v-if="themeConfig.showSize" class="item"></me-size-select>
Expand Down
3 changes: 2 additions & 1 deletion src/locales/lang/en/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@
"去": "Go",
"操作失败,请稍后重试":"Operation failed, please try again later",
"返回值解析失败":"Failed to parse the return value",
"请求异常,请联系管理员":"The request is abnormal, Please contact the administrator"
"请求异常,请联系管理员":"The request is abnormal, Please contact the administrator",
"搜索":"Search"
}
8 changes: 8 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ export const router = createRouter({
routes: flatteningRoutes2(constantRoutes),
});

export const jump = (route:Pick<RouteRecordRaw,"path"|"meta">)=>{
if(route.meta?.isLink){
window.open(route.path,'_blank');
}else{
router.push(route.path);
}
}

/**
*
* @param app
Expand Down

0 comments on commit f42271c

Please sign in to comment.