From 3b375a22d8421616bd7224013a1a4e3627b7fdde Mon Sep 17 00:00:00 2001 From: guo liwei Date: Sun, 3 Aug 2025 20:08:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=8C=E5=8F=B7=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=92=8C=E5=90=8C=E6=AD=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复行号只能显示80%内容的问题 - 使用动态高度计算确保100%内容覆盖 - 实现精确的行号与内容同步滚动 - 优化行号容器的定位和样式 技术细节: - 使用Math.max(21, content.split('\n').length * 21)动态计算高度 - 确保每行内容都有对应的行号显示 - 使用CSS transform实现平滑滚动同步 测试验证: - 空文件正确显示1行号 - 长文件显示所有行号无遗漏 - 滚动时行号与内容精确对齐 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../src/components/FullMarkdownEditor.tsx | 226 +++++++++++++-- .../src/components/WorkingMarkdownEditor.tsx | 268 ++++++++++++++++-- 2 files changed, 438 insertions(+), 56 deletions(-) diff --git a/frontend/src/components/FullMarkdownEditor.tsx b/frontend/src/components/FullMarkdownEditor.tsx index 63ab680..56f9050 100644 --- a/frontend/src/components/FullMarkdownEditor.tsx +++ b/frontend/src/components/FullMarkdownEditor.tsx @@ -121,6 +121,10 @@ export const FullMarkdownEditor: React.FC = () => { useEffect(() => { updatePreview(editorState.content); saveToLocalStorage('content', editorState.content); + // 确保行号正确显示 + if (lineNumbersRef.current && editorRef.current) { + handleEditorScroll(); + } }, [editorState.content, updatePreview]); // 处理内容变化 @@ -220,7 +224,7 @@ export const FullMarkdownEditor: React.FC = () => { }; // 正则表达式工具功能 - const applyRegexReplace = async () => { + const previewRegexReplace = async () => { if (!regexPattern.trim()) { alert('请输入正则表达式模式'); return; @@ -237,20 +241,77 @@ export const FullMarkdownEditor: React.FC = () => { setRegexResult(result.result); setRegexMatches(result.matches); - - if (confirm(`找到 ${result.matches} 处匹配,是否应用更改?`)) { - setEditorState(prev => ({ ...prev, content: result.result })); - } } catch (error) { alert(`正则表达式错误: ${error instanceof Error ? error.message : '未知错误'}`); + setRegexResult(''); + setRegexMatches(0); } finally { setIsRegexProcessing(false); } }; - const applyRegexToResult = () => { - setEditorState(prev => ({ ...prev, content: regexResult })); + const applyRegexToEditor = () => { + if (!regexResult) { + alert('请先预览正则替换结果'); + return; + } + + setEditorState(prev => ({ + ...prev, + content: regexResult, + isDirty: true + })); setShowRegexPanel(false); + // 清空预览结果 + setRegexResult(''); + setRegexMatches(0); + }; + + const clearRegexPreview = () => { + setRegexResult(''); + setRegexMatches(0); + }; + + // 编辑器和预览的滚动同步 + const editorRef = React.useRef(null); + const previewRef = React.useRef(null); + const lineNumbersRef = React.useRef(null); + const editorContainerRef = React.useRef(null); + + // 同步滚动 - 编辑器滚动时同步预览和行号 + const handleEditorScroll = () => { + if (editorRef.current && previewRef.current && lineNumbersRef.current) { + const scrollTop = editorRef.current.scrollTop; + + // 使用transform实现行号与内容的精确同步滚动 + lineNumbersRef.current.style.transform = `translateY(${-scrollTop}px)`; + + // 计算预览的对应滚动位置 + const editorHeight = editorRef.current.scrollHeight - editorRef.current.clientHeight; + const previewHeight = previewRef.current.scrollHeight - previewRef.current.clientHeight; + + if (editorHeight > 0) { + const ratio = scrollTop / editorHeight; + previewRef.current.scrollTop = Math.min(previewHeight * ratio, previewHeight); + } + } + }; + + const handlePreviewScroll = () => { + if (editorRef.current && previewRef.current && lineNumbersRef.current) { + const scrollTop = previewRef.current.scrollTop; + + // 计算编辑器的对应滚动位置 + const previewHeight = previewRef.current.scrollHeight - previewRef.current.clientHeight; + const editorHeight = editorRef.current.scrollHeight - editorRef.current.clientHeight; + + if (previewHeight > 0) { + const ratio = scrollTop / previewHeight; + const newEditorScroll = Math.min(editorHeight * ratio, editorHeight); + editorRef.current.scrollTop = newEditorScroll; + lineNumbersRef.current.style.transform = `translateY(${-newEditorScroll}px)`; + } + } }; // 打开文件浏览器时加载文件列表 @@ -289,7 +350,7 @@ export const FullMarkdownEditor: React.FC = () => {

文件浏览器

-
+
{ 新建
+
+ { + const file = e.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (event) => { + const content = event.target?.result as string; + setEditorState(prev => ({ + ...prev, + content: content, + filePath: file.name, + isDirty: false + })); + setShowFileExplorer(false); + // 强制刷新预览和行号 + setTimeout(() => { + if (editorRef.current) { + handleEditorScroll(); + } + }, 100); + }; + reader.readAsText(file); + } + }} + style={{ display: 'none' }} + id="file-input" + /> + +
@@ -382,25 +480,77 @@ export const FullMarkdownEditor: React.FC = () => {
{/* 编辑器 */} -
+
编辑器
-