懒羊羊
2024-01-31 e57a8990ae56f657a59c435a0613c5f7a8728003
提交 | 用户 | 时间
e57a89 1 <template>
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       const path = val.path;
74       const query = val.query;
75       if(this.ishttp(val.path)) {
76         // http(s):// 路径新窗口打开
77         const pindex = path.indexOf("http");
78         window.open(path.substr(pindex, path.length), "_blank");
79       } else {
80         if (query) {
81           this.$router.push({ path: path, query: JSON.parse(query) });
82         } else {
83           this.$router.push(path)
84         }
85       }
86       this.search = ''
87       this.options = []
88       this.$nextTick(() => {
89         this.show = false
90       })
91     },
92     initFuse(list) {
93       this.fuse = new Fuse(list, {
94         shouldSort: true,
95         threshold: 0.4,
96         location: 0,
97         distance: 100,
98         minMatchCharLength: 1,
99         keys: [{
100           name: 'title',
101           weight: 0.7
102         }, {
103           name: 'path',
104           weight: 0.3
105         }]
106       })
107     },
108     // Filter out the routes that can be displayed in the sidebar
109     // And generate the internationalized title
110     generateRoutes(routes, basePath = '/', prefixTitle = []) {
111       let res = []
112
113       for (const router of routes) {
114         // skip hidden router
115         if (router.hidden) { continue }
116
117         const data = {
118           path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
119           title: [...prefixTitle]
120         }
121
122         if (router.meta && router.meta.title) {
123           data.title = [...data.title, router.meta.title]
124
125           if (router.redirect !== 'noRedirect') {
126             // only push the routes with title
127             // special case: need to exclude parent router without redirect
128             res.push(data)
129           }
130         }
131
132         if (router.query) {
133           data.query = router.query
134         }
135
136         // recursive child routes
137         if (router.children) {
138           const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
139           if (tempRoutes.length >= 1) {
140             res = [...res, ...tempRoutes]
141           }
142         }
143       }
144       return res
145     },
146     querySearch(query) {
147       if (query !== '') {
148         this.options = this.fuse.search(query)
149       } else {
150         this.options = []
151       }
152     },
153     ishttp(url) {
154       return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
155     }
156   }
157 }
158 </script>
159
160 <style lang="scss" scoped>
161 .header-search {
162   font-size: 0 !important;
163
164   .search-icon {
165     cursor: pointer;
166     font-size: 18px;
167     vertical-align: middle;
168   }
169
170   .header-search-select {
171     font-size: 18px;
172     transition: width 0.2s;
173     width: 0;
174     overflow: hidden;
175     background: transparent;
176     border-radius: 0;
177     display: inline-block;
178     vertical-align: middle;
179
180     ::v-deep .el-input__inner {
181       border-radius: 0;
182       border: 0;
183       padding-left: 0;
184       padding-right: 0;
185       box-shadow: none !important;
186       border-bottom: 1px solid #d9d9d9;
187       vertical-align: middle;
188     }
189   }
190
191   &.show {
192     .header-search-select {
193       width: 210px;
194       margin-left: 10px;
195     }
196   }
197 }
198 </style>