Skip to content

Commit 759bfe8

Browse files
feature: 新增搜索框功能,快捷键:Ctrl + F
1 parent 3f5049a commit 759bfe8

File tree

9 files changed

+136
-55
lines changed

9 files changed

+136
-55
lines changed

packages/gui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"request-progress": "^3.0.0",
3535
"sass": "^1.81.0",
3636
"sass-loader": "^16.0.3",
37+
"search-bar-vue2": "^1.0.0",
3738
"vue": "^2.7.16",
3839
"vue-json-editor-fix-cn": "^1.4.3",
3940
"vue-router": "^3.6.5"

packages/gui/src/background.js

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -298,28 +298,38 @@ function createWindow (startHideWindow, autoQuitIfError = true) {
298298
})
299299

300300
const shortcut = (event, input) => {
301-
// 按 F12,打开/关闭 开发者工具
302-
if (input.key === 'F12') {
303-
// 阻止默认的按键事件行为
301+
if (input.key === 'F12' && input.type === 'keyUp' && !input.control && !input.shift && !input.alt && !input.meta) {
302+
// 按 F12,打开/关闭 开发者工具
304303
event.preventDefault()
305-
// 切换开发者工具显示状态
306304
switchDevTools()
307-
// eslint-disable-next-line style/brace-style
308-
}
309-
// 按 F5,刷新页面
310-
else if (input.key === 'F5') {
311-
// 阻止默认的按键事件行为
305+
} else if (input.key === 'F5' && input.type === 'keyUp' && !input.control && !input.shift && !input.alt && !input.meta) {
306+
// 按 F5,刷新页面
312307
event.preventDefault()
313-
// 刷新页面
314308
win.webContents.reload()
309+
} else {
310+
// 全文检索框(SearchBar)相关快捷键
311+
if ((input.key === 'F' || input.key === 'f') && input.type === 'keyDown' && input.control && !input.shift && !input.alt && !input.meta) {
312+
// 按 Ctrl + F,显示或隐藏全文检索框(SearchBar)
313+
event.preventDefault()
314+
win.webContents.send('search-bar', { key: 'show-hide' })
315+
} else if (input.key === 'Escape' && input.type === 'keyUp' && !input.control && !input.shift && !input.alt && !input.meta) {
316+
// 按 ESC,隐藏全文检索框(SearchBar)
317+
event.preventDefault()
318+
win.webContents.send('search-bar', { key: 'show-hide', hideSearchBar: true })
319+
} else if (input.key === 'F3' && input.type === 'keyDown' && !input.control && !input.shift && !input.alt && !input.meta) {
320+
// 按 F3,全文检索框(SearchBar)定位到下一个
321+
event.preventDefault()
322+
win.webContents.send('search-bar', { key: 'next' })
323+
} else if (input.key === 'F3' && input.type === 'keyDown' && !input.control && input.shift && !input.alt && !input.meta) {
324+
// 按 Shift + F3,全文检索框(SearchBar)定位到上一个
325+
event.preventDefault()
326+
win.webContents.send('search-bar', { key: 'previous' })
327+
}
315328
}
316329
}
317330

318331
// 监听键盘事件
319332
win.webContents.on('before-input-event', (event, input) => {
320-
if (input.type !== 'keyUp' || input.control || input.alt || input.shift || input.meta) {
321-
return
322-
}
323333
win.webContents.executeJavaScript('config')
324334
.then((value) => {
325335
console.info('window.config:', value, ', key:', input.key)

packages/gui/src/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import antd from 'ant-design-vue'
22
import Vue from 'vue'
33
import VueRouter from 'vue-router'
4+
import SearchBar from 'search-bar-vue2'
45
import { ipcRenderer } from 'electron'
56
import view from './view'
67
import App from './view/App.vue'
@@ -25,6 +26,7 @@ try {
2526
Vue.config.productionTip = false
2627
Vue.use(antd)
2728
Vue.use(VueRouter)
29+
Vue.use(SearchBar)
2830
Vue.component(DsContainer)
2931
// 3. 创建 router 实例,然后传 `routes` 配置
3032
// 你还可以传别的配置参数, 不过先这么简单着吧。

packages/gui/src/view/App.vue

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
<script>
2+
import { ipcRenderer } from 'electron'
3+
import { SearchBar } from 'search-bar-vue2'
24
import createMenus from '@/view/router/menu'
35
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
46
import { colorTheme } from './composables/theme'
57
68
export default {
79
name: 'App',
810
components: {
11+
SearchBar,
912
},
1013
data () {
1114
return {
1215
locale: zhCN,
1316
info: {},
1417
menus: undefined,
1518
config: undefined,
19+
hideSearchBar: true,
1620
}
1721
},
1822
computed: {
@@ -37,16 +41,48 @@ export default {
3741
this.$api.info.get().then((ret) => {
3842
this.info = ret
3943
})
44+
45+
ipcRenderer.on('search-bar', (_, message) => {
46+
console.info(_, message)
47+
if (message.key === 'show-hide') {
48+
if (window.config.disableSearchBar) {
49+
this.hideSearchBar = true
50+
return
51+
}
52+
53+
this.hideSearchBar = message.hideSearchBar != null ? message.hideSearchBar : !this.hideSearchBar
54+
55+
// 显示后,获取输入框焦点
56+
if (!this.hideSearchBar) {
57+
setTimeout(() => {
58+
try {
59+
this.$refs.searchBar.$el.querySelector('input').focus()
60+
} catch {
61+
}
62+
}, 100)
63+
}
64+
} else {
65+
// 如果还未显示检索框,先显示出来
66+
if (this.hideSearchBar) {
67+
this.hideSearchBar = false
68+
return
69+
}
70+
71+
if (message.key === 'next' && !this.hideSearchBar) {
72+
this.$refs.searchBar.next()
73+
} else if (message.key === 'previous' && !this.hideSearchBar) {
74+
this.$refs.searchBar.previous()
75+
}
76+
}
77+
})
4078
},
4179
methods: {
42-
handleClick (e) {
43-
console.log('click', e)
44-
},
4580
titleClick (item) {
4681
console.log('title click:', item)
4782
},
4883
menuClick (item) {
4984
console.log('menu click:', item)
85+
window.config.disableSearchBar = false
5086
this.$router.replace(item.path)
5187
},
5288
},
@@ -56,6 +92,12 @@ export default {
5692
<template>
5793
<a-config-provider :locale="locale">
5894
<div class="ds_layout" :class="themeClass">
95+
<SearchBar ref="searchBar"
96+
:root="'#document'"
97+
:highlightClass="'search-bar-highlight'"
98+
:selectedClass="'selected-highlight'"
99+
:hiden.sync="hideSearchBar"
100+
/>
59101
<a-layout>
60102
<a-layout-sider :theme="theme">
61103
<div class="logo" />
@@ -82,7 +124,7 @@ export default {
82124
</a-layout-sider>
83125
<a-layout>
84126
<!-- <a-layout-header>Header</a-layout-header> -->
85-
<a-layout-content>
127+
<a-layout-content id="document">
86128
<router-view />
87129
</a-layout-content>
88130
<a-layout-footer>
@@ -144,4 +186,11 @@ body {
144186
border: 0;
145187
}
146188
}
189+
.search-bar-highlight {
190+
background-color: #ef0fff;
191+
192+
&.selected-highlight {
193+
background-color: #38d878;
194+
}
195+
}
147196
</style>

packages/gui/src/view/api.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ export function apiInit (app) {
2727
ipcRenderer.removeAllListeners(channel)
2828
},
2929
invoke,
30+
postMessage (channel, ...args) {
31+
ipcRenderer.postMessage(channel, ...args)
32+
},
3033
send,
3134
async openExternal (href) {
3235
await shell.openExternal(href)

packages/gui/src/view/pages/server.vue

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,18 @@ export default {
170170
},
171171
async handleTabChange (key) {
172172
if (key !== '2' && key !== '3' && key !== '5' && key !== '6' && key !== '7') {
173-
return
174-
}
173+
// 没有 JsonEditor
174+
window.config.disableSearchBar = false
175+
} else {
176+
// 有 JsonEditor
177+
window.config.disableSearchBar = true
178+
this.$api.ipc.postMessage('search-bar', { key: 'show-hide', hideSearchBar: true })
175179
176-
// 规避 vue-json-editor 内容只填充输入框一半的问题
177-
setTimeout(() => {
178-
window.dispatchEvent(new Event('resize'))
179-
}, 10)
180+
// 规避 vue-json-editor 内容只填充输入框一半的问题
181+
setTimeout(() => {
182+
window.dispatchEvent(new Event('resize'))
183+
}, 10)
184+
}
180185
},
181186
},
182187
}
@@ -271,7 +276,7 @@ export default {
271276
</a-tab-pane>
272277
<a-tab-pane key="2" tab="拦截设置">
273278
<VueJsonEditor
274-
ref="editor" v-model="config.server.intercepts" style="height:100%" mode="code"
279+
ref="editor2" v-model="config.server.intercepts" style="height:100%" mode="code"
275280
:show-btns="false" :expanded-on-start="true"
276281
/>
277282
</a-tab-pane>
@@ -284,7 +289,7 @@ export default {
284289
<hr style="margin-bottom:15px">
285290
<div>这里指定域名的超时时间:<span class="form-help">(域名配置可使用通配符或正则)</span></div>
286291
<VueJsonEditor
287-
ref="editor" v-model="config.server.setting.timeoutMapping" style="flex-grow:1;min-height:300px;margin-top:10px" mode="code"
292+
ref="editor3" v-model="config.server.setting.timeoutMapping" style="flex-grow:1;min-height:300px;margin-top:10px" mode="code"
288293
:show-btns="false" :expanded-on-start="true"
289294
/>
290295
</div>
@@ -320,7 +325,7 @@ export default {
320325
说明:<code>自动兼容程序</code>会自动根据错误信息进行兼容性调整,并将兼容设置保存在 <code>~/.dev-sidecar/automaticCompatibleConfig.json</code> 文件中。但并不是所有的兼容设置都是正确的,所以需要通过以下配置来覆盖错误的兼容设置。
321326
</div>
322327
<VueJsonEditor
323-
ref="editor" v-model="config.server.compatible" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
328+
ref="editor5" v-model="config.server.compatible" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
324329
:show-btns="false" :expanded-on-start="true"
325330
/>
326331
</div>
@@ -332,14 +337,14 @@ export default {
332337
<span class="form-help">(域名配置可使用通配符或正则)</span>
333338
</div>
334339
<VueJsonEditor
335-
ref="editor" v-model="config.server.preSetIpList" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
340+
ref="editor6" v-model="config.server.preSetIpList" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
336341
:show-btns="false" :expanded-on-start="true"
337342
/>
338343
</div>
339344
</a-tab-pane>
340345
<a-tab-pane key="7" tab="DNS服务管理">
341346
<VueJsonEditor
342-
ref="editor" v-model="config.server.dns.providers" style="height:100%" mode="code"
347+
ref="editor7" v-model="config.server.dns.providers" style="height:100%" mode="code"
343348
:show-btns="false" :expanded-on-start="true"
344349
/>
345350
</a-tab-pane>

packages/gui/src/view/pages/setting.vue

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,18 @@ export default {
4848
case 'ArrowDown':
4949
case 'ArrowLeft':
5050
case 'ArrowRight':
51-
return ''
51+
return ''
52+
53+
// 不支持监听以下几个键,返回空
54+
case 'NumpadDivide': // return 'Num/'
55+
case 'NumpadMultiply': // return 'Num*'
56+
case 'NumpadDecimal': // return 'Num.'
57+
case 'NumpadSubtract': // return 'Num-'
58+
case 'NumpadAdd': // return 'Num+'
59+
return ''
5260
}
5361
5462
switch (event.code) {
55-
// F1 ~ F12
56-
case 'F1': return 'F1'
57-
case 'F2': return 'F2'
58-
case 'F3': return 'F3'
59-
case 'F4': return 'F4'
60-
case 'F5': return 'F5'
61-
case 'F6': return 'F6'
62-
case 'F7': return 'F7'
63-
case 'F8': return 'F8'
64-
case 'F9': return 'F9'
65-
case 'F10': return 'F10'
66-
case 'F11': return 'F11'
67-
case 'F12': return 'F12'
68-
6963
// 0 ~ 9
7064
case 'Digit0': return '0'
7165
case 'Digit1': return '1'
@@ -110,14 +104,6 @@ export default {
110104
case 'Numpad8': return 'Num8'
111105
case 'Numpad9': return 'Num9'
112106
case 'Numpad0': return 'Num0'
113-
114-
// 不支持监听以下几个键,返回空
115-
case 'NumpadDivide': // return 'Num/'
116-
case 'NumpadMultiply': // return 'Num*'
117-
case 'NumpadDecimal': // return 'Num.'
118-
case 'NumpadSubtract': // return 'Num-'
119-
case 'NumpadAdd': // return 'Num+'
120-
return ''
121107
}
122108
123109
// 字母
@@ -126,7 +112,7 @@ export default {
126112
}
127113
128114
console.error(`未能识别的按键:key=${event.key}, code=${event.code}, keyCode=${event.keyCode}`)
129-
return ''
115+
return ''
130116
},
131117
async disableBeforeInputEvent () {
132118
clearTimeout(window.enableBeforeInputEventTimeout)
@@ -169,15 +155,19 @@ export default {
169155
shortcut += 'Meta + '
170156
}
171157
172-
// 如果以上按钮都没有按下,并且当前键不是F1~F4、F6~F11时,则直接返回(注:F5已经是刷新页面快捷键、F12已经是打开DevTools的快捷键了)
173-
if (shortcut === '' && !key.match(/^F([1-46-9]|1[01])$/g)) {
158+
// 如果以上按钮都没有按下,并且当前键不是F1、F2、F4、F6~F11时,则直接返回(注:F5已经是刷新页面快捷键、F12已经是打开DevTools的快捷键了)
159+
if (shortcut === '' && !key.match(/^F([1246-9]|1[01])$/g)) {
174160
this.config.app.showHideShortcut = ''
175161
return
176162
}
177163
178164
// 拼接键值
179165
shortcut += key
180166
167+
if (shortcut === 'Ctrl + F' || shortcut === 'Shift + F3') {
168+
shortcut = '' // 如果是其他已被占用快捷键,则设置为 '无'
169+
}
170+
181171
this.config.app.showHideShortcut = shortcut
182172
},
183173
async applyBefore () {
@@ -430,7 +420,7 @@ export default {
430420
<a-form-item label="打开窗口快捷键" :label-col="labelCol" :wrapper-col="wrapperCol">
431421
<a-input v-model="config.app.showHideShortcut" @change="shortcutChange" @keydown="shortcutKeyDown" @keyup="shortcutKeyUp" />
432422
<div class="form-help">
433-
部分快捷键已被占用:F5=刷新页面,F12=开发者工具(DevTools)
423+
部分快捷键已被占用:<code>F5</code>、<code>F12</code>、<code>Ctrl+F</code>、<code>F3</code>、<code>Shift+F3</code>
434424
</div>
435425
</a-form-item>
436426
<a-form-item label="启动时窗口状态" :label-col="labelCol" :wrapper-col="wrapperCol">

packages/gui/src/view/style/theme/dark.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,13 @@ $dark-input: #777; //输入框:背景色
239239
border-color: #8b2929;
240240
}
241241
}
242+
243+
.search-bar {
244+
div {
245+
color: #000;
246+
}
247+
span {
248+
color: #000;
249+
}
250+
}
242251
}

pnpm-lock.yaml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)