chore: 收口复查遗留项并补 radiogroup 键盘导航

This commit is contained in:
2026-08-08 18:46:43 +08:00
parent 45451c0d49
commit 5cbce86e03
6 changed files with 53 additions and 4 deletions
+44 -4
View File
@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { ThemeMode } from '../composables/useDarkMode'
import { useDarkMode } from '../composables/useDarkMode'
import { computed } from 'vue'
import { computed, nextTick, ref } from 'vue'
const { theme, isDark, setTheme } = useDarkMode()
@@ -17,6 +17,39 @@ const modeOptions: { value: ThemeMode; label: string; description: string }[] =
{ value: 'dark', label: '深色', description: '始终使用深色模式' },
{ value: 'auto', label: '跟随系统', description: '根据系统设置自动切换' },
]
const optionEls = ref<HTMLButtonElement[]>([])
const activeIndex = computed(() =>
Math.max(0, modeOptions.findIndex((option) => option.value === theme.value)),
)
function setOptionRef(el: unknown, index: number): void {
if (el) {
optionEls.value[index] = el as HTMLButtonElement
}
}
function focusOption(index: number): void {
const next = (index + modeOptions.length) % modeOptions.length
setTheme(modeOptions[next].value)
void nextTick(() => optionEls.value[next]?.focus())
}
function onKeydown(event: KeyboardEvent): void {
if (event.key === 'ArrowDown' || event.key === 'ArrowRight') {
event.preventDefault()
focusOption(activeIndex.value + 1)
} else if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {
event.preventDefault()
focusOption(activeIndex.value - 1)
} else if (event.key === 'Home') {
event.preventDefault()
focusOption(0)
} else if (event.key === 'End') {
event.preventDefault()
focusOption(modeOptions.length - 1)
}
}
</script>
<template>
@@ -31,15 +64,22 @@ const modeOptions: { value: ThemeMode; label: string; description: string }[] =
当前生效<strong>{{ currentEffectiveMode }}</strong>
</div>
<div class="dark-mode-settings__options" role="radiogroup" aria-label="主题模式">
<div
class="dark-mode-settings__options"
role="radiogroup"
aria-label="主题模式"
@keydown="onKeydown"
>
<button
v-for="option in modeOptions"
v-for="(option, index) in modeOptions"
:key="option.value"
type="button"
role="radio"
class="dark-mode-settings__option"
:class="{ 'is-active': theme === option.value }"
:aria-checked="theme === option.value"
:tabindex="theme === option.value ? 0 : -1"
:ref="(el: unknown) => { setOptionRef(el, index) }"
@click="setTheme(option.value)"
>
<div class="dark-mode-settings__option-label">{{ option.label }}</div>
@@ -137,4 +177,4 @@ const modeOptions: { value: ThemeMode; label: string; description: string }[] =
font-size: 0.8125rem;
color: var(--halo-text-tertiary);
}
</style>
</style>