想的到會用到的套件都差不多裝完了,最後來提升一點閱讀體驗,自從某次加班一段時間過勞產生了肘隧道症候群後,除了換直立滑鼠,調整坐姿,買夠高的椅子以外,也讓自己習慣75%的鍵盤(100%的鍵盤太大,會卡住滑鼠移動,造成正常坐姿下左右不平衡),也開始越來越習慣盡量用純鍵盤的方式寫程式和爬文,所以今天來添加一點鍵盤操作吧。
鍵盤控制 Composable
把鍵盤事件註冊的核心邏輯抽出來做成 Composable
,然後根據頁面或元件的需要,獨立為每個頁面或元件做按鍵事件宣告。
ts
type Key = string;
type KeyCombination = string;
interface KeyBoardControlConfig {
[key: string]: () => void
}
const keyStrategies: { [key in Key]: () => void } = {};
const combinationStrategies: { [key in KeyCombination]: () => void } = {};
function keyDownHandler(event: KeyboardEvent, showKey: boolean) {
const key = event.key;
if (key in keyStrategies) {
keyStrategies[key]();
}
const combination = `${event.ctrlKey ? 'Ctrl+' : ''}${event.shiftKey ? 'Shift+' : ''}${event.altKey ? 'Alt+' : ''}${key}`;
if (combination in combinationStrategies) {
combinationStrategies[combination]();
}
if (showKey) {
console.log('key:', key);
console.log('combination:', combination);
}
}
export default (config: KeyBoardControlConfig, showKey: boolean) => {
for (const key in config) {
if (key.includes('+')) {
combinationStrategies[key] = config[key];
} else if (key.length === 1) {
keyStrategies[key] = config[key];
}
// } else {
// codeStrategies[key] = config[key];
// }
}
onMounted(() => {
window.addEventListener('keydown', event => keyDownHandler(event, showKey));
});
onBeforeUnmount(() => {
window.removeEventListener('keydown', event => keyDownHandler(event, showKey));
});
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
showKey
這個參數是拿來決定是否在按鍵時 console key name 的,只是為了 Debug 方便,完全是可以不用加沒關係。
在擴展 Layout 宣告事件
在 docs/.vitepress/theme/layout/expandLayout.vue
中註冊事件。
vue
<script setup lang="ts">
import DefaultTheme from 'vitepress/theme';
import { useData, useRouter } from 'vitepress';
import useKeyBoardControl from '@hooks/useKeyBoardControl';
function selectorClickHandler(selector: string) {
const element = document.querySelector(selector) as HTMLElement;
if (element) {
element.click();
}
}
function getOutlines() {
const outlines = document.querySelectorAll('.VPDocOutlineItem.root .outline-link');
const activeIndex = Array.from(outlines).findIndex(outline => outline.classList.contains('active'));
return {
outlines,
activeIndex
};
}
useKeyBoardControl({
'ArrowLeft': () => {
selectorClickHandler('.pager-link.prev');
},
'ArrowRight': () => {
selectorClickHandler('.pager-link.next');
},
'Ctrl+ArrowUp': () => {
const { outlines, activeIndex } = getOutlines();
if (outlines.length <= 0)
return;
if (activeIndex > 0) {
const prevIndex = activeIndex - 1;
if (prevIndex >= 0) {
(outlines[prevIndex] as HTMLElement).click();
}
} else {
window.scrollTo(0, 0); // 頁面卷軸到最上面
}
},
'Ctrl+ArrowDown': () => {
const { outlines, activeIndex } = getOutlines();
if (outlines.length > 0) {
const nextIndex = activeIndex + 1;
if (nextIndex < outlines.length) {
(outlines[nextIndex] as HTMLElement).click();
}
}
}
}, true);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
看程式碼可以發現,我們註冊了四個事件
- 按下方向鍵 → 的時候,會按下一篇文章的按鈕一下
- 按下方向鍵 ← 的時候,會按上一篇文章的按鈕一下
- 按下 Ctrl + ↑ 的時候,會往上一個目錄條目移動,如果已在第一個則移到最上面。
- 按下 Ctrl + ↓ 的時候,會往下一個目錄條目移動
短時間內也想不到還有什麼事件需要增加的了。
卷軸體驗優化
不過在移動目錄的時候,會發現他是直接跳過去的,使用體驗有點差,我們在 docs/.vitepress/theme/scss/basic.scss
裡面添加:
scss
html {
scroll-behavior: smooth;
}
1
2
3
2
3
這樣他就會滑順的移動過去囉~