From a47b9f95bc2a93d0d35bdd1201f9988319401dd8 Mon Sep 17 00:00:00 2001 From: thzxx <1440196015@qq.com> Date: Fri, 24 Jul 2026 17:46:42 +0800 Subject: [PATCH] =?UTF-8?q?fix(core):=20robust=20syntax=20highlight=20?= =?UTF-8?q?=E2=80=94=20dynamic=20positioning,=20mode-aware,=20proper=20tog?= =?UTF-8?q?gle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _positionHighlightLayer(): set left offset dynamically from gutter width - Use hidden attribute instead of clearing innerHTML for toggle - Skip highlight in preview mode - Initialize highlightLayer hidden state on construction - Remove hardcoded left:36px CSS --- src/core.js | 26 ++++++++++++++++++++++---- src/styles.js | 6 ++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/core.js b/src/core.js index 626e42b..0280f45 100644 --- a/src/core.js +++ b/src/core.js @@ -233,6 +233,9 @@ class MarkdownEditor { if (this.config.syntaxHighlight) { textarea.classList.add('me-textarea-highlight'); } + if (highlightLayer && !this.config.syntaxHighlight) { + highlightLayer.hidden = true; + } editorInner.appendChild(textarea); editorPane.appendChild(editorInner); @@ -1329,12 +1332,13 @@ class MarkdownEditor { } _doHighlight() { + if (!this.highlightLayer || this.highlightLayer.hidden || this._mode === 'preview') return; const text = this._value || ''; if (!text) { this.highlightLayer.innerHTML = ''; return; } - // 超过 50KB 跳过,避免大文档卡顿 if (text.length > 50000) { this.highlightLayer.innerHTML = escapeHTML(text) + '\n'; return; } let html = escapeHTML(text); + this._positionHighlightLayer(); // 正则按优先级:先匹配更具体的模式,避免被泛模式吞掉 // 1. 图片(先于链接) @@ -1370,13 +1374,27 @@ class MarkdownEditor { if (this.textarea) { this.textarea.classList.toggle('me-textarea-highlight', this.config.syntaxHighlight); } - if (!this.config.syntaxHighlight && this.highlightLayer) { - this.highlightLayer.innerHTML = ''; + if (this.highlightLayer) { + this.highlightLayer.hidden = !this.config.syntaxHighlight; + } + if (this.config.syntaxHighlight) { + this._positionHighlightLayer(); + this._doHighlight(); } - if (this.config.syntaxHighlight) this._doHighlight(); return this; } + _positionHighlightLayer() { + if (!this.highlightLayer) return; + // 动态设置左边距:有行号时对齐行号宽度,无行号时从 0 开始 + if (this.gutter && this.config.lineNumbers && this.gutter.style.display !== 'none') { + const w = this.gutter.getBoundingClientRect().width; + this.highlightLayer.style.left = w + 'px'; + } else { + this.highlightLayer.style.left = '0'; + } + } + _updateWordCount() { if (!this.config.wordCount || !this.statusEl) return; const text = this._value || ''; diff --git a/src/styles.js b/src/styles.js index 40c3056..d5c0864 100644 --- a/src/styles.js +++ b/src/styles.js @@ -134,13 +134,15 @@ const generateCSS = () => { .me-editor-inner { display: flex; height: 100%; overflow: hidden; position: relative; } /* 语法高亮叠加层(v0.1.14) */ .me-highlight-layer { - position: absolute; top: 0; left: 36px; right: 0; bottom: 0; + position: absolute; top: 0; right: 0; bottom: 0; padding: 16px 18px; margin: 0; border: 0; outline: 0; overflow: hidden; font-family: var(--md-mono); font-size: 13.5px; line-height: 1.7; white-space: pre-wrap; word-wrap: break-word; pointer-events: none; background: transparent; - color: var(--md-text); + color: var(--md-text); z-index: 0; } + /* 隐藏高亮层(语法高亮关闭时) */ + .me-highlight-layer[hidden] { display: none; } .mh-heading { color: var(--md-accent); font-weight: 700; } .mh-bold { color: var(--md-text); font-weight: 700; } .mh-italic { font-style: italic; }