vue3导航栏菜单搜索功能

效果图

在这里插入图片描述

组件封装 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;
  }
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值