fix(core): robust syntax highlight — dynamic positioning, mode-aware, proper toggle

- _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
This commit is contained in:
2026-07-24 17:46:42 +08:00
parent 8b776185ab
commit a47b9f95bc
2 changed files with 26 additions and 6 deletions
+22 -4
View File
@@ -233,6 +233,9 @@ class MarkdownEditor {
if (this.config.syntaxHighlight) { if (this.config.syntaxHighlight) {
textarea.classList.add('me-textarea-highlight'); textarea.classList.add('me-textarea-highlight');
} }
if (highlightLayer && !this.config.syntaxHighlight) {
highlightLayer.hidden = true;
}
editorInner.appendChild(textarea); editorInner.appendChild(textarea);
editorPane.appendChild(editorInner); editorPane.appendChild(editorInner);
@@ -1329,12 +1332,13 @@ class MarkdownEditor {
} }
_doHighlight() { _doHighlight() {
if (!this.highlightLayer || this.highlightLayer.hidden || this._mode === 'preview') return;
const text = this._value || ''; const text = this._value || '';
if (!text) { this.highlightLayer.innerHTML = ''; return; } if (!text) { this.highlightLayer.innerHTML = ''; return; }
// 超过 50KB 跳过,避免大文档卡顿
if (text.length > 50000) { this.highlightLayer.innerHTML = escapeHTML(text) + '\n'; return; } if (text.length > 50000) { this.highlightLayer.innerHTML = escapeHTML(text) + '\n'; return; }
let html = escapeHTML(text); let html = escapeHTML(text);
this._positionHighlightLayer();
// 正则按优先级:先匹配更具体的模式,避免被泛模式吞掉 // 正则按优先级:先匹配更具体的模式,避免被泛模式吞掉
// 1. 图片(先于链接) // 1. 图片(先于链接)
@@ -1370,13 +1374,27 @@ class MarkdownEditor {
if (this.textarea) { if (this.textarea) {
this.textarea.classList.toggle('me-textarea-highlight', this.config.syntaxHighlight); this.textarea.classList.toggle('me-textarea-highlight', this.config.syntaxHighlight);
} }
if (!this.config.syntaxHighlight && this.highlightLayer) { if (this.highlightLayer) {
this.highlightLayer.innerHTML = ''; this.highlightLayer.hidden = !this.config.syntaxHighlight;
}
if (this.config.syntaxHighlight) {
this._positionHighlightLayer();
this._doHighlight();
} }
if (this.config.syntaxHighlight) this._doHighlight();
return this; 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() { _updateWordCount() {
if (!this.config.wordCount || !this.statusEl) return; if (!this.config.wordCount || !this.statusEl) return;
const text = this._value || ''; const text = this._value || '';
+4 -2
View File
@@ -134,13 +134,15 @@ const generateCSS = () => {
.me-editor-inner { display: flex; height: 100%; overflow: hidden; position: relative; } .me-editor-inner { display: flex; height: 100%; overflow: hidden; position: relative; }
/* 语法高亮叠加层(v0.1.14 */ /* 语法高亮叠加层(v0.1.14 */
.me-highlight-layer { .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; padding: 16px 18px; margin: 0; border: 0; outline: 0; overflow: hidden;
font-family: var(--md-mono); font-size: 13.5px; line-height: 1.7; font-family: var(--md-mono); font-size: 13.5px; line-height: 1.7;
white-space: pre-wrap; word-wrap: break-word; white-space: pre-wrap; word-wrap: break-word;
pointer-events: none; background: transparent; 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-heading { color: var(--md-accent); font-weight: 700; }
.mh-bold { color: var(--md-text); font-weight: 700; } .mh-bold { color: var(--md-text); font-weight: 700; }
.mh-italic { font-style: italic; } .mh-italic { font-style: italic; }