效果图
![在这里插入图片描述](https://img-blog.csdnimg.cn/70bfb4f3f8de4b068b5a809bbfff9051.png)
组件封装 HeaderSearch.vue
<script setup lang="ts">
import { nextTick, ref, watch } from "vue";
import { tabStore } from "@/store/tab";
import { loginStore } from "@/store/login";
import { CommonMethod } from "@/util/commonMethod";
import router from "@/router";
const login = loginStore();
const show = ref(false);
const headerSearchSelect = ref();
const options = ref([]);
const search = ref();
const tab = tabStore();
const click = () => {
show.value = !show.value;
if (show.value) {
headerSearchSelect.value && headerSearchSelect.value.focus();
}
};
const close = () => {
headerSearchSelect.value && headerSearchSelect.value.blur();
options.value = [];
show.value = false;
};
const change = (val) => {
tab.selectMenu(val);
router.push(val.path);
search.value = "";
options.value = [];
nextTick(() => {
show.value = false;
});
};
const querySearch = (query) => {
if (query !== "") {
let temp = CommonMethod.TreeToList(login.menu);
temp = temp.filter((ele) => {
return (
ele.path !== "/login" && ele.path !== "/" && ele.path !== "/register"
);
});
options.value = temp.filter((ele) => {
return ele.meta.title.indexOf(query) !== -1;
});
} else {
options.value = [];
}
};
watch(show, (newValue) => {
if (newValue) {
document.body.addEventListener("click", close);
} else {
document.body.removeEventListener("click", close);
}
});
</script>
<template>
<el-button link :class="{ show: show }" class="header-search">
<i class="iconfont icon-shujuchaxun menuImgColor" @click.stop="click"></i>
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="Search"
class="header-search-select"
@change="change"
>
<el-option
v-for="item in options"
:key="item.path"
:value="item"
:label="item.meta.title"
/>
</el-select>
</el-button>
</template>
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
::deep(.el-input__inner) {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
}
}
}
.menuImgColor {
color: white;
font-size: 20px;
line-height: 50px;
}
</style>
CommonMethod.ts(Tree转List)
export class CommonMethod {
private static TreeToList(tree: any) {
let returnList: any[] = [];
tree.forEach((ele: any) => {
const temp = {
...ele,
};
returnList.push(temp);
if (temp.children) {
returnList = returnList.concat(CommonMethod.TreeToList(ele.children));
}
});
return returnList;
}
}