houzhongjian
2024-07-11 759b1c71011abd6b58c37d2566f3f3c208c2f1b2
提交 | 用户 | 时间
759b1c 1 <template>
H 2   <div :class="{'show':show}" class="header-search">
3     <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
4     <el-select
5       ref="headerSearchSelect"
6       v-model="search"
7       :remote-method="querySearch"
8       filterable
9       default-first-option
10       remote
11       placeholder="Search"
12       class="header-search-select"
13       @change="change"
14     >
15       <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
16     </el-select>
17   </div>
18 </template>
19
20 <script>
21 // fuse is a lightweight fuzzy-search module
22 // make search results more in line with expectations
23 import Fuse from 'fuse.js/dist/fuse.min.js'
24 import path from 'path'
25
26 export default {
27   name: 'HeaderSearch',
28   data() {
29     return {
30       search: '',
31       options: [],
32       searchPool: [],
33       show: false,
34       fuse: undefined
35     }
36   },
37   computed: {
38     routes() {
39       return this.$store.getters.permission_routes
40     }
41   },
42   watch: {
43     routes() {
44       this.searchPool = this.generateRoutes(this.routes)
45     },
46     searchPool(list) {
47       this.initFuse(list)
48     },
49     show(value) {
50       if (value) {
51         document.body.addEventListener('click', this.close)
52       } else {
53         document.body.removeEventListener('click', this.close)
54       }
55     }
56   },
57   mounted() {
58     this.searchPool = this.generateRoutes(this.routes)
59   },
60   methods: {
61     click() {
62       this.show = !this.show
63       if (this.show) {
64         this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
65       }
66     },
67     close() {
68       this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
69       this.options = []
70       this.show = false
71     },
72     change(val) {
73       if(this.ishttp(val.path)) {
74         // http(s):// 路径新窗口打开
75         window.open(val.path, "_blank");
76       } else {
77         this.$router.push(val.path)
78       }
79       this.search = ''
80       this.options = []
81       this.$nextTick(() => {
82         this.show = false
83       })
84     },
85     initFuse(list) {
86       this.fuse = new Fuse(list, {
87         shouldSort: true,
88         threshold: 0.4,
89         location: 0,
90         distance: 100,
91         minMatchCharLength: 1,
92         keys: [{
93           name: 'title',
94           weight: 0.7
95         }, {
96           name: 'path',
97           weight: 0.3
98         }]
99       })
100     },
101     // Filter out the routes that can be displayed in the sidebar
102     // And generate the internationalized title
103     generateRoutes(routes, basePath = '/', prefixTitle = []) {
104       let res = []
105
106       for (const router of routes) {
107         // skip hidden router
108         if (router.hidden) { continue }
109
110         const data = {
111           path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
112           title: [...prefixTitle]
113         }
114
115         if (router.meta && router.meta.title) {
116           data.title = [...data.title, router.meta.title]
117
118           if (router.redirect !== 'noRedirect') {
119             // only push the routes with title
120             // special case: need to exclude parent router without redirect
121             res.push(data)
122           }
123         }
124
125         // recursive child routes
126         if (router.children) {
127           const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
128           if (tempRoutes.length >= 1) {
129             res = [...res, ...tempRoutes]
130           }
131         }
132       }
133       return res
134     },
135     querySearch(query) {
136       if (query !== '') {
137         this.options = this.fuse.search(query)
138       } else {
139         this.options = []
140       }
141     },
142     ishttp(url) {
143       return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
144     }
145   }
146 }
147 </script>
148
149 <style lang="scss" scoped>
150 .header-search {
151   font-size: 0 !important;
152
153   .search-icon {
154     cursor: pointer;
155     font-size: 18px;
156     vertical-align: middle;
157   }
158
159   .header-search-select {
160     font-size: 18px;
161     transition: width 0.2s;
162     width: 0;
163     overflow: hidden;
164     background: transparent;
165     border-radius: 0;
166     display: inline-block;
167     vertical-align: middle;
168
169     :deep(.el-input__inner) {
170       border-radius: 0;
171       border: 0;
172       padding-left: 0;
173       padding-right: 0;
174       box-shadow: none !important;
175       border-bottom: 1px solid #d9d9d9;
176       vertical-align: middle;
177     }
178   }
179
180   &.show {
181     .header-search-select {
182       width: 210px;
183       margin-left: 10px;
184     }
185   }
186 }
187 </style>