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