vue3管理后台项目增加菜单搜索功能

一、添加搜索组件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/>



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值