成绩录入页面优化
This commit is contained in:
1 parent
53bee58a84
commit
7124011da9
3 files changed
+234
-54
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
type Direction = 'up' | 'down' | 'left' | 'right'
|
||||
|
||||
/**
|
||||
* Makes an editable score table behave like a spreadsheet without changing
|
||||
* the normal keyboard behaviour of selects, switches, or free-text fields.
|
||||
*/
|
||||
export function useScoreGridNavigation(grid: string) {
|
||||
function handleScoreGridKeydown(event: KeyboardEvent) {
|
||||
const directionByKey: Record<string, Direction | undefined> = {
|
||||
Enter: 'down',
|
||||
ArrowUp: 'up',
|
||||
ArrowDown: 'down',
|
||||
ArrowLeft: 'left',
|
||||
ArrowRight: 'right',
|
||||
}
|
||||
const direction = directionByKey[event.key]
|
||||
if (!direction) return
|
||||
|
||||
const current = event.currentTarget as HTMLElement
|
||||
const row = Number(current.dataset.scoreRow)
|
||||
const column = Number(current.dataset.scoreColumn)
|
||||
if (!Number.isFinite(row) || !Number.isFinite(column)) return
|
||||
|
||||
const cells = Array.from(
|
||||
document.querySelectorAll<HTMLElement>(`[data-score-grid="${grid}"]`),
|
||||
).filter((cell) => {
|
||||
const input = cell.querySelector<HTMLInputElement>('input')
|
||||
return input && !input.disabled && !input.readOnly
|
||||
})
|
||||
|
||||
const findCell = (targetRow: number, targetColumn: number) =>
|
||||
cells.find((cell) =>
|
||||
Number(cell.dataset.scoreRow) === targetRow
|
||||
&& Number(cell.dataset.scoreColumn) === targetColumn)
|
||||
|
||||
let target: HTMLElement | undefined
|
||||
if (direction === 'left' || direction === 'right') {
|
||||
const rowCells = cells
|
||||
.filter((cell) => Number(cell.dataset.scoreRow) === row)
|
||||
.sort((left, right) => Number(left.dataset.scoreColumn) - Number(right.dataset.scoreColumn))
|
||||
const currentIndex = rowCells.indexOf(current)
|
||||
target = rowCells[currentIndex + (direction === 'left' ? -1 : 1)]
|
||||
} else {
|
||||
const columnCells = cells
|
||||
.filter((cell) => Number(cell.dataset.scoreColumn) === column)
|
||||
.sort((top, bottom) => Number(top.dataset.scoreRow) - Number(bottom.dataset.scoreRow))
|
||||
const currentIndex = columnCells.indexOf(current)
|
||||
target = columnCells[currentIndex + (direction === 'up' ? -1 : 1)]
|
||||
?? findCell(row + (direction === 'up' ? -1 : 1), column)
|
||||
}
|
||||
|
||||
// Keep arrow keys from changing an input-number value; navigation is the
|
||||
// expected spreadsheet action even at an edge where no next cell exists.
|
||||
event.preventDefault()
|
||||
if (!target) return
|
||||
|
||||
void nextTick(() => {
|
||||
const input = target?.querySelector<HTMLInputElement>('input')
|
||||
input?.focus()
|
||||
input?.select()
|
||||
})
|
||||
}
|
||||
|
||||
return { handleScoreGridKeydown }
|
||||
}
|
||||
Reference in new issue
Block a user