From db699f0c419007ed8e5606dacdfd52ed4f158691 Mon Sep 17 00:00:00 2001 From: Linkon <116425752+Linkon-lcw@users.noreply.github.com> Date: Sun, 18 Jan 2026 21:29:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=AF=BC=E8=88=AA):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BF=AB=E9=80=9F=E5=AF=BC=E8=88=AA=E6=BB=91=E5=8A=A8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E4=BA=A4=E4=BA=92=E4=BD=93?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在快速导航组件中添加滑动选择功能,提升操作便捷性 - 移除单个导航项的点击事件,改为父容器统一处理 - 禁用全局文本选择,但保留输入框的文本选择功能 - 将滚动行为从平滑滚动改为自动滚动以提高响应速度 --- src/renderer/src/assets/main.css | 6 +++ src/renderer/src/components/Home.tsx | 58 +++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/renderer/src/assets/main.css b/src/renderer/src/assets/main.css index fb02805..9617bae 100644 --- a/src/renderer/src/assets/main.css +++ b/src/renderer/src/assets/main.css @@ -8,6 +8,12 @@ body, margin: 0; padding: 0; overflow: hidden; + user-select: none; /* 禁用文本选择 */ +} + +/* 如果某些输入框需要允许选择,可以单独开启 */ +input, textarea { + user-select: text; } .ss-sidebar { diff --git a/src/renderer/src/components/Home.tsx b/src/renderer/src/components/Home.tsx index 9288228..0724486 100644 --- a/src/renderer/src/components/Home.tsx +++ b/src/renderer/src/components/Home.tsx @@ -210,7 +210,7 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => { const scrollToGroup = (key: string) => { const element = groupRefs.current[key] if (element) { - element.scrollIntoView({ behavior: 'smooth', block: 'start' }) + element.scrollIntoView({ behavior: 'auto', block: 'start' }) } } @@ -398,12 +398,56 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => { )) } + // 快速导航滑动处理 + const navContainerRef = useRef(null) + const isNavDragging = useRef(false) + + const handleNavAction = useCallback((clientY: number) => { + if (!navContainerRef.current) return + const rect = navContainerRef.current.getBoundingClientRect() + const y = clientY - rect.top + const items = navContainerRef.current.children + const itemCount = items.length + if (itemCount === 0) return + + // 计算当前指向第几个项 + const itemHeight = rect.height / itemCount + const index = Math.floor(y / itemHeight) + const safeIndex = Math.max(0, Math.min(itemCount - 1, index)) + + const targetGroup = groupedStudents[safeIndex] + if (targetGroup) { + scrollToGroup(targetGroup.key) + } + }, [groupedStudents]) + + const onNavMouseDown = (e: React.MouseEvent) => { + isNavDragging.current = true + handleNavAction(e.clientY) + document.addEventListener('mousemove', onGlobalMouseMove) + document.addEventListener('mouseup', onGlobalMouseUp) + } + + const onGlobalMouseMove = (e: MouseEvent) => { + if (isNavDragging.current) { + handleNavAction(e.clientY) + } + } + + const onGlobalMouseUp = () => { + isNavDragging.current = false + document.removeEventListener('mousemove', onGlobalMouseMove) + document.removeEventListener('mouseup', onGlobalMouseUp) + } + // 渲染快速导航 const renderQuickNav = () => { if (groupedStudents.length <= 1 || sortType === 'score' || (sortType === 'alphabet' && searchKeyword)) return null return (
= ({ canEdit }) => { transform: 'translateY(-50%)', display: 'flex', flexDirection: 'column', - gap: '2px', backgroundColor: 'var(--ss-card-bg)', padding: '8px 4px', borderRadius: '20px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', zIndex: 100, maxHeight: '80vh', - overflowY: 'auto', - border: '1px solid var(--ss-border-color)' + border: '1px solid var(--ss-border-color)', + cursor: 'pointer', + userSelect: 'none' }} > {groupedStudents.map((group) => (
scrollToGroup(group.key)} style={{ width: '24px', height: '24px', @@ -435,12 +478,9 @@ export const Home: React.FC<{ canEdit: boolean }> = ({ canEdit }) => { fontSize: '11px', fontWeight: 'bold', color: 'var(--td-brand-color)', - cursor: 'pointer', borderRadius: '50%', - transition: 'background 0.2s' + pointerEvents: 'none' // 让事件由父容器统一处理 }} - onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = 'var(--td-brand-color-1)')} - onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = 'transparent')} > {group.key}