前端实现菜单搜索搜索(功能模版)

目录

前言

总体界面如下所示:

在这里插入图片描述

正文

<template>
  <div class="avue-searchs"
       @click.self="handleEsc">
    <div class="avue-searchs__title">菜单搜索</div>
    <div class="avue-searchs__content">
      <div class="avue-searchs__form">
        <el-input :placeholder="$t('search')"
                  v-model="value"
                  @keydown.esc.native="handleEsc">
          <el-button slot="append"
                     icon="el-icon-search"></el-button>
        </el-input>
        <p>
          <el-tag>你可以使用快捷键esc 关闭</el-tag>
        </p>
      </div>
      <div class="avue-searchs__list">
        <el-scrollbar class="avue-searchs__scrollbar">
          <div class="avue-searchs__item"
               v-for="(item,index) in menus"
               :key="index"
               @click="handleSelect(item)">
            <i :class="[item[iconKey],'avue-searchs__item-icon']"></i>
            <span class="avue-searchs__item-title">{{item[labelKey]}}</span>
            <div class="avue-searchs__item-path">
              {{item[pathKey]}}
            </div>
          </div>
        </el-scrollbar>
      </div>
    </div>
  </div>
</template>

<script>
  import config from './sidebar/config.js'
  import {mapGetters} from "vuex";

  export default {
    data() {
      return {
        config: config,
        value: "",
        menus: [],
        menuList: []
      }
    },
    created() {
      this.getMenuList();
    },
    watch: {
      value() {
        this.querySearch();
      },
      menu() {
        this.getMenuList();
      }
    },
    computed: {
      labelKey() {
        return this.website.menu.props.label || this.config.propsDefault.label;
      },
      pathKey() {
        return this.website.menu.props.path || this.config.propsDefault.path;
      },
      iconKey() {
        return this.website.menu.props.icon || this.config.propsDefault.icon;
      },
      childrenKey() {
        return (
          this.website.menu.props.children || this.config.propsDefault.children
        );
      },
      ...mapGetters(["menu", "website"])
    },
    methods: {
      handleEsc() {
        this.$parent.isSearch = false;
      },
      getMenuList() {
        const findMenu = list => {
          for (let i = 0; i < list.length; i++) {
            const ele = Object.assign({}, list[i]);
            if (this.validatenull(ele[this.childrenKey])) {
              this.menuList.push(ele);
            } else {
              findMenu(ele[this.childrenKey]);
            }
          }
        };
        this.menuList = [];
        findMenu(this.menu);
        this.menus = this.menuList;
      },
      querySearch() {
        var restaurants = this.menuList;
        var queryString = this.value
        this.menus = queryString
          ? this.menuList.filter(this.createFilter(queryString))
          : restaurants;
      },
      createFilter(queryString) {
        return restaurant => {
          return (
            restaurant.name.toLowerCase().indexOf(queryString.toLowerCase()) ===
            0
          );
        };
      },
      handleSelect(item) {
        this.handleEsc();
        this.value = "";
        this.$router.push({
          path: this.$router.$avueRouter.getPath({
            name: item[this.labelKey],
            src: item[this.pathKey]
          }, item.meta),
          query: item.query
        });
      }
    }
  }
</script>

<style lang="scss" scoped>
  .avue-searchs {
    padding-top: 50px;
    width: 100%;
    height: 100%;
    background-color: #fff;
    z-index: 1024;

    &__title {
      margin-bottom: 60px;
      text-align: center;
      font-size: 42px;
      font-weight: bold;
      letter-spacing: 2px;
      text-indent: 2px;
    }

    &__form {
      margin: 0 auto 50px auto;
      width: 50%;
      text-align: center;

      p {
        margin-top: 20px;
      }
    }

    &__scrollbar {
      height: 400px;
    }

    &__list {
      box-sizing: border-box;
      padding: 20px 30px;
      margin: 0 auto;
      width: 70%;
      border-radius: 4px;
      border: 1px solid #ebeef5;
      background-color: #fff;
      overflow: hidden;
      color: #303133;
      transition: 0.3s;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    }

    &__item {
      padding: 5px 0;
      border-bottom: 1px dashed #eee;

      &-icon {
        margin-right: 5px;
        font-size: 18px;
      }

      &-title {
        font-size: 20px;
        font-weight: 500;
        color: #333;
      }

      &-path {
        line-height: 30px;
        color: #666;
      }
    }
  }
</style>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农研究僧

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值