From 178af5c36300a4388456db48f2aab0de05a6fe5c Mon Sep 17 00:00:00 2001 From: rohow Date: Fri, 30 Jan 2026 15:56:40 +0800 Subject: [PATCH] feat(lineNumbers): enhance element metrics by adding marginTop and marginBottom --- src/alpine/post-line-num.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/alpine/post-line-num.ts b/src/alpine/post-line-num.ts index 47e9a1e..aa04c18 100644 --- a/src/alpine/post-line-num.ts +++ b/src/alpine/post-line-num.ts @@ -20,6 +20,8 @@ interface LineSpanOptions { interface ElementMetrics { top: number; height: number; + marginTop: number; + marginBottom: number; paddingTop: number; lineHeight: number; lines: number; @@ -56,7 +58,7 @@ const isEmptyElement = (element: HTMLElement): boolean => { return !element.textContent?.trim(); }; -const getStyleValue = (style: CSSStyleDeclaration, prop: 'paddingTop' | 'paddingBottom' | 'lineHeight' | 'fontSize'): number => +const getStyleValue = (style: CSSStyleDeclaration, prop: 'paddingTop' | 'paddingBottom' | 'lineHeight' | 'fontSize' | 'marginTop' | 'marginBottom'): number => parseFloat(style[prop]) || 0; const getDefaultLineHeight = (element: HTMLElement): number => { @@ -70,6 +72,8 @@ const getElementMetrics = (element: HTMLElement, containerRect: DOMRect, default const style = getComputedStyle(element); const paddingTop = getStyleValue(style, 'paddingTop'); const paddingBottom = getStyleValue(style, 'paddingBottom'); + const marginTop = getStyleValue(style, 'marginTop'); + const marginBottom = getStyleValue(style, 'marginBottom'); const height = element.offsetHeight; const contentHeight = height - paddingTop - paddingBottom; const isNonText = isNonTextElement(tagName); @@ -80,6 +84,8 @@ const getElementMetrics = (element: HTMLElement, containerRect: DOMRect, default return { top: element.getBoundingClientRect().top - containerRect.top, height, + marginTop, + marginBottom, paddingTop, lineHeight: contentHeight / lines, lines, @@ -222,18 +228,23 @@ export const postLineNum = (): LineNumbersState => ({ })); } - if (lastBottom > 0 && metrics.top > lastBottom) { + // 计算实际的内容起始位置(考虑 margin-top) + const contentStart = metrics.top - metrics.marginTop; + + // 只有当间隙足够大时才填充行号 + if (lastBottom > 0 && contentStart > lastBottom) { currentLine = appendGapLines({ fragment, gapStart: lastBottom, - gapEnd: metrics.top, + gapEnd: contentStart, lineHeight: defaultLineHeight, startLine: currentLine }); } currentLine = appendElementLines(fragment, metrics, currentLine); - lastBottom = metrics.top + metrics.height; + // 更新 lastBottom,包含 margin-bottom + lastBottom = metrics.top + metrics.height + metrics.marginBottom; } // 派发初始化滚动高亮事件