From 76aaf921dc755e0f095e62344bed659da86e7070 Mon Sep 17 00:00:00 2001
From: loulijun2021 <1694218219@qq.com>
Date: 星期二, 20 十二月 2022 12:08:38 +0800
Subject: [PATCH] 1.面包屑右上角新增搜索菜单功能
---
src/icons/svg/search.svg | 1
src/layout/components/Navbar.vue | 35 +++++---
package.json | 1
src/components/HeaderSearch/index.vue | 190 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 215 insertions(+), 12 deletions(-)
diff --git a/package.json b/package.json
index 427342e..686353e 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,7 @@
"element-themex": "^1.0.3",
"eslint": "6.7.2",
"eslint-plugin-vue": "6.2.2",
+ "fuse.js": "^6.6.2",
"html-webpack-plugin": "3.2.0",
"mockjs": "1.0.1-beta3",
"px2rem-loader": "^0.1.9",
diff --git a/src/components/HeaderSearch/index.vue b/src/components/HeaderSearch/index.vue
new file mode 100644
index 0000000..20a42aa
--- /dev/null
+++ b/src/components/HeaderSearch/index.vue
@@ -0,0 +1,190 @@
+<template>
+ <div :class="{'show':show}" class="header-search">
+ <svg-icon class-name="search-icon" icon-class="search" style="color:#A7A7A7;" @click.stop="click" />
+ <el-select
+ ref="headerSearchSelect"
+ v-model="search"
+ :remote-method="querySearch"
+ filterable
+ default-first-option
+ remote
+ placeholder="鑿滃崟鎼滅储"
+ class="header-search-select"
+ @change="change"
+ >
+
+ <el-option v-for="item in options" :key="item.path" :value="item" :label="item.item.title.join('>')" />
+ </el-select>
+ </div>
+</template>
+
+<script>
+// fuse is a lightweight fuzzy-search module
+// make search results more in line with expectations
+import Fuse from 'fuse.js'
+import path from 'path'
+
+export default {
+ name: 'HeaderSearch',
+ data() {
+ return {
+ search: '',
+ options: [],
+ searchPool: [],
+ show: false,
+ fuse: undefined
+ }
+ },
+ computed: {
+ routes() {
+ return this.$store.getters.permission_routes
+ }
+ },
+ watch: {
+ routes() {
+ this.searchPool = this.generateRoutes(this.routes)
+ },
+ searchPool(list) {
+ this.initFuse(list)
+ },
+ show(value) {
+ if (value) {
+ document.body.addEventListener('click', this.close)
+ } else {
+ document.body.removeEventListener('click', this.close)
+ }
+ }
+ },
+ mounted() {
+ this.searchPool = this.generateRoutes(this.routes)
+
+ console.log(this.searchPool)
+ },
+ methods: {
+ click() {
+ this.show = !this.show
+ if (this.show) {
+ this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
+ }
+ },
+ close() {
+ this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
+ this.options = []
+ this.show = false
+ },
+ change(val) {
+ console.log(val, 1)
+ this.$router.push(val.item.path)
+ this.search = ''
+ this.options = []
+ this.$nextTick(() => {
+ this.show = false
+ })
+ },
+ initFuse(list) {
+ this.fuse = 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
+ }]
+ })
+ },
+ // Filter out the routes that can be displayed in the sidebar
+ // And generate the internationalized title
+ generateRoutes(routes, basePath = '/', prefixTitle = []) {
+ // console.log(routes, 1)
+ let res = []
+
+ for (const router of routes) {
+ // skip hidden router
+ 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') {
+ // only push the routes with title
+ // special case: need to exclude parent router without redirect
+ res.push(data)
+ }
+ }
+
+ // recursive child routes
+ if (router.children) {
+ const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+ if (tempRoutes.length >= 1) {
+ res = [...res, ...tempRoutes]
+ }
+ }
+ }
+ // console.log(res, 2)
+ return res
+ },
+ querySearch(query) {
+ if (query !== '') {
+ this.options = this.fuse.search(query)
+ } else {
+ this.options = []
+ }
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.header-search {
+ font-size: 0 !important;
+
+ .search-icon {
+ cursor: pointer;
+ font-size: 18px;
+ vertical-align: middle;
+ }
+
+ .svg-icon:hover{
+ color: #42b983 !important;
+ }
+
+ .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;
+
+ ::v-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;
+ }
+ }
+}
+</style>
diff --git a/src/icons/svg/search.svg b/src/icons/svg/search.svg
new file mode 100644
index 0000000..84233dd
--- /dev/null
+++ b/src/icons/svg/search.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M124.884 109.812L94.256 79.166c-.357-.357-.757-.629-1.129-.914a50.366 50.366 0 0 0 8.186-27.59C101.327 22.689 78.656 0 50.67 0 22.685 0 0 22.688 0 50.663c0 27.989 22.685 50.663 50.656 50.663 10.186 0 19.643-3.03 27.6-8.201.286.385.557.771.9 1.114l30.628 30.632a10.633 10.633 0 0 0 7.543 3.129c2.728 0 5.457-1.043 7.543-3.115 4.171-4.157 4.171-10.915.014-15.073M50.671 85.338C31.557 85.338 16 69.78 16 50.663c0-19.102 15.557-34.661 34.67-34.661 19.115 0 34.657 15.559 34.657 34.675 0 19.102-15.557 34.661-34.656 34.661"/></svg>
\ No newline at end of file
diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue
index 298570f..cafa44b 100644
--- a/src/layout/components/Navbar.vue
+++ b/src/layout/components/Navbar.vue
@@ -5,12 +5,27 @@
<breadcrumb class="breadcrumb-container" />
<div class="right-menu">
+
+ <template v-if="device!=='mobile'">
+ <search id="header-search" class="right-menu-item" />
+
+ <!-- <error-log class="errLog-container right-menu-item hover-effect" />-->
+
+ <!-- <screenfull id="screenfull" class="right-menu-item hover-effect" />-->
+
+ <!-- <el-tooltip content="Global Size" effect="dark" placement="bottom">-->
+ <!-- <size-select id="size-select" class="right-menu-item hover-effect" />-->
+ <!-- </el-tooltip>-->
+
+ </template>
+
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<!-- <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">-->
<div style="display: flex;align-items: center;margin-top: -5px">
- <div class="headerImg"><i class="el-icon-user" /></div>
- <div class="headerName">{{ username }}</div>
+
+ <i class="el-icon-user" style="font-weight: bolder;font-size: 18px;margin-right: 5px;color:#A7A7A7" />
+ <div style=" font-size: 18px;font-family: 'Microsoft YaHei';color:#AAAAAA">{{ username }}</div>
</div>
<!-- <i class="el-icon-caret-bottom" />-->
@@ -74,17 +89,20 @@
import Hamburger from '@/components/Hamburger'
import { getCookie } from '@/utils/auth'
import { UpdateUserPassword } from '@/api/user'
+import Search from '@/components/HeaderSearch'
const SER_HZ = /^[\u4e00-\u9fa5]+$/
export default {
components: {
Breadcrumb,
- Hamburger
+ Hamburger,
+ Search
},
computed: {
...mapGetters([
'sidebar',
- 'avatar'
+ 'avatar',
+ 'device'
])
},
created() {
@@ -206,6 +224,7 @@
float: right;
height: 100%;
line-height: 50px;
+ display: flex;
&:focus {
outline: none;
@@ -236,14 +255,6 @@
margin-top: 5px;
position: relative;
cursor: pointer;
-
- .headerImg {
- margin: 5px;
- }
-
- .headerName {
- font-weight: bolder;
- }
.user-avatar {
cursor: pointer;
--
Gitblit v1.9.3