一、添加搜索组件HeaderSearch.vue
<template>
<div class="m-headerSearch">
<el-tooltip
effect="dark"
content="菜单搜索"
placement="bottom"
v-if="isSearchIcon"
>
<svg
t="1719890704626"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="5731"
width="18"
height="18"
class="bell header-icon"
style="font-size: 22px"
@click="handleSearch"
>
<path
d="M417.383062 781.594111c-62.535265 0-124.161834-16.698311-179.426509-49.300846-81.562621-48.080042-139.525754-125.07053-163.182546-216.743416s-10.1952-187.094142 37.913495-268.656763c48.080042-81.533968 125.07053-139.497101 216.743416-163.153894 91.701538-23.77038 187.094142-10.223852 268.656763 37.884842S737.613434 246.722194 761.270227 338.394057l0 0c23.656793 91.672886 10.1952 187.094142-37.913495 268.629133-48.108694 81.562621-125.099183 139.525754-216.772069 163.182546C477.05 777.816065 447.11727 781.594111 417.383062 781.594111zM418.518932 130.511449c-24.848944 0-49.868781 3.152806-74.547857 9.54233-76.649727 19.766183-141.002384 68.214614-181.187619 136.4016-40.213887 68.186985-51.458999 147.932214-31.69384 224.553289 19.793812 76.649727 68.214614 141.002384 136.4016 181.187619 68.186985 40.212864 147.903561 51.402717 224.553289 31.69384 76.649727-19.793812 141.002384-68.214614 181.216271-136.4016 40.212864-68.158333 51.458999-147.932214 31.665187-224.553289l0 0c-19.766183-76.649727-68.186985-141.002384-136.372947-181.216271C522.317996 144.456043 470.801692 130.511449 418.518932 130.511449z"
p-id="5732"
></path>
<path
d="M915.563312 953.295682c-11.161201 0-22.321378-4.260024-30.841426-12.780071l-260.307607-260.421194c-17.039072-17.039072-17.039072-44.672432 0-61.682851 17.039072-17.039072 44.64378-17.039072 61.682851 0l260.307607 260.421194c17.039072 17.039072 17.039072 44.672432 0 61.682851C937.88469 949.035658 926.723489 953.295682 915.563312 953.295682z"
p-id="5733"
></path>
</svg>
</el-tooltip>
<el-select
ref="headerSearchSelect"
v-model="search"
style="width: 100%"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="请输入菜单名称"
class="header-search-select"
@change="change"
@blur="selectBlur"
v-if="isShowSearch"
>
<el-option
v-for="item in options"
:key="item.item.path"
:value="item.item.path"
:label="
item &&
item.item.title &&
item.item.title.length &&
item.item.title.join(' > ')
"
>
</el-option>
</el-select>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from "vue";
import path from "path-browserify";
import Fuse from "fuse.js";
import { useRouter } from "vue-router";
const router = useRouter();
const isShowSearch = ref(false);
const isSearchIcon = ref(true);
const options: any = ref([]);
const searchPool = ref([]);
const search = ref("");
const fuse = ref(null);
const headerSearchSelect: any = ref(null); // el-select 的引用
import { usePermissionStore } from "@/store/modules/permission";
const PermissionStore = usePermissionStore();
const routes = computed(() => PermissionStore.routes);
const handleSearch = () => {
isShowSearch.value = true;
isSearchIcon.value = false;
setTimeout(() => {
if (headerSearchSelect.value) {
headerSearchSelect.value.focus(); // 让 el-select 获取焦点
}
}, 1);
};
const selectBlur = () => {
isShowSearch.value = false;
isSearchIcon.value = true;
};
const initFuse = (list) => {
fuse.value = new Fuse(list, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
{
name: "title",
weight: 0.7,
},
{
name: "path",
weight: 0.3,
},
],
});
};
watch(searchPool, (list) => {
initFuse(list);
});
// 筛选出可以在侧栏中显示的路线 生成标题
const generateRoutes = (routes, basePath = "/", prefixTitle = []) => {
let res = [];
for (const router of routes) {
// 忽略隐藏的路由
if (router.hidden) {
continue;
}
const data = {
path: path.resolve(basePath, router.path),
title: [...prefixTitle],
};
if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title];
if (router.redirect !== "noRedirect") {
// 仅推送带有标题的路由
// 特殊情况:需要排除无重定向的父路由器
res.push(data);
}
}
// 递归子路由
if (router.children) {
const tempRoutes = generateRoutes(router.children, data.path, data.title);
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes];
}
}
}
return res;
};
const change = (val) => {
if (val) {
router.push({
path: val,
});
}
options.value = [];
search.value = "";
isShowSearch.value = false;
};
onMounted(() => {
searchPool.value = generateRoutes(JSON.parse(JSON.stringify(routes.value)));
});
const querySearch = (query) => {
if (query !== "") {
options.value = fuse.value.search(query);
} else {
options.value = [];
}
};
</script>
<style lang="scss" scoped>
.m-headerSearch {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
.item-info-pop {
display: flex;
align-items: center;
}
.bell {
color: black;
}
.item-child {
display: flex;
align-items: center;
font-size: 13px;
}
}
.transverseMenu {
.bell {
color: white;
}
}
/* 菜单搜索样式 */
.m-headerSearch {
:deep(.el-dialog) {
.el-dialog__header {
display: none;
}
.el-dialog__body {
padding: 0;
}
}
.header-search-select {
height: 30px;
:deep(.el-input__wrapper) {
height: 30px;
}
}
}
</style>
二、安装fuse.js
1.使用 npm 安装 npm install fuse.js
2.使用 yarn 安装 yarn add fuse.js
三、在Navbar.vue中引入组件使用
<HeaderSearch/>
08-01
349
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
09-22
147
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
06-27
4438
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
04-09
456
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)