header.vue 3.7 KB
<template>
  <el-header class="layout-header">
    <div class="left">
      <img class="logo" src="/img/logo.svg" />
      <span class="title">{{ appName }}</span>
      <template v-if="activeMenu === '/component'">
        <el-divider class="divider" direction="vertical"></el-divider>
        <el-autocomplete
          v-model="searchKey"
          :fetch-suggestions="querySearch"
          placeholder="搜索组件"
          :trigger-on-focus="false"
          @select="handleSelectMenu"
          prefix-icon="el-icon-search"
          class="autocomplete"
          popper-class="search"
          size="small"
          clearable
        >
          <div slot-scope="{ item }">
            <div class="search-option">
              <span>{{ item.title }}</span>
              <span class="group">{{ item.group }}</span>
            </div>
          </div>
        </el-autocomplete>
      </template>
    </div>
    <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect">
      <el-menu-item v-for="(data, index) in pages" :key="index" :index="data.meta.path">{{ data.meta.title }}</el-menu-item>
    </el-menu>
  </el-header>
</template>

<script>
import { pages, components } from '@/router/routes';

export default {
  name: 'layoutHeader',
  data() {
    let componentList = [];
    components.forEach((data, index) => {
      if (data.children && data.children.length > 0) {
        data.children.forEach(item => {
          componentList.push({ group: data.group, name: item.name, ...item.meta });
        });
      }
    });
    return {
      appName: process.env.VUE_APP_NAME,
      activeMenu: '/index',
      components: componentList,
      pages: pages.map((data, index) => {
        const param = data.meta && data.meta.path ? {} : { meta: { title: `Page - ${index}`, path: '/index' } }
        return { ...data, ...param }
      }),
      searchKey: undefined,
    }
  },
  created() {
    const { matched = [] } = this.$route || {};
    const route = matched[0] || {};
    this.activeMenu = route.path || '/index';
  },
  methods: {
    querySearch(queryString, cb) {
      var components = this.components;
      var results = queryString ? components.filter(this.createFilter(queryString)) : components;
      // 调用 callback 返回建议列表的数据
      cb(results);
    },
    createFilter(queryString) {
      return (component) => {
        return (component.name.toLowerCase().indexOf(queryString.toLowerCase()) >= 0);
      };
    },
    handleSelect(key) {
      if (key && this.$route.path !== key) {
        this.$router.push({ path: key });
      }
    },
    handleSelectMenu({ name }) {
      this.$emit('menu-change', name);
    }
  }
}
</script>

<style lang="scss">
.layout-header {
  position: fixed;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .04) !important;
  height: 60px;
  width: 100%;
  z-index: 10;
  padding: 0 60px !important;
  .el-menu.el-menu--horizontal {
    border: 0;
  }
  .left {
    display: flex;
    align-items: center;
    .logo {
      height: 40px;
      padding-right: 10px;
    }
    .title {
      font-weight: bold;
      font-size: 20px;
      background-image: -webkit-linear-gradient(bottom, #333, #666);
      background-clip: text;
      -webkit-text-fill-color: transparent;
    }
    .divider {
      margin: 0 20px;
    }
    .autocomplete {
      input {
        border-top: 0;
        border-left: 0;
        border-right: 0;
        border-radius: 0;
      }
    }
  }
}
.search {
  min-width: 300px;
  .search-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-weight: 600;
    .group {
      color: #d9d9d9;
    }
  }
}
</style>