diff --git a/src/composables/useScreenCapture.ts b/src/composables/useScreenCapture.ts index 0e67f2fa..02dbf3bf 100644 --- a/src/composables/useScreenCapture.ts +++ b/src/composables/useScreenCapture.ts @@ -4,7 +4,12 @@ */ import { ref } from 'vue' import { captureAsImageData } from '@/utils/snapCapture' -import { resolveCaptureBoxSizing, waitForCaptureLayoutStabilization } from '@/utils/captureLayout' +import { + restoreCapturePadding, + resolveCaptureBoxSizing, + snapshotCapturePadding, + waitForCaptureLayoutStabilization, +} from '@/utils/captureLayout' import { useToast } from '@/composables/useToast' import { useLayoutStore } from '@/stores/layout' import { usePlatformService } from '@/services' @@ -137,8 +142,7 @@ export function useScreenCapture() { captureError.value = null // 截图外框只由显式选项开启,普通卡片截图不改变原布局。 - const originalPadding = element.style.padding - const originalPaddingBottom = element.style.paddingBottom + const originalPadding = snapshotCapturePadding(element.style, options?.captureFrame === true) const originalBoxSizing = element.style.boxSizing const originalPosition = element.style.position const originalWidth = element.style.width @@ -439,8 +443,7 @@ export function useScreenCapture() { watermark.remove() // 恢复元素样式 - element.style.padding = originalPadding - element.style.paddingBottom = originalPaddingBottom + restoreCapturePadding(element.style, originalPadding) element.style.boxSizing = originalBoxSizing element.style.position = originalPosition element.style.width = originalWidth diff --git a/src/utils/captureLayout.test.ts b/src/utils/captureLayout.test.ts index 9185bf40..893ea321 100644 --- a/src/utils/captureLayout.test.ts +++ b/src/utils/captureLayout.test.ts @@ -1,6 +1,56 @@ import { describe, it } from 'node:test' import assert from 'node:assert/strict' -import { resolveCaptureBoxSizing, waitForCaptureLayoutStabilization } from './captureLayout' +import { + restoreCapturePadding, + resolveCaptureBoxSizing, + snapshotCapturePadding, + waitForCaptureLayoutStabilization, +} from './captureLayout' + +describe('inline padding restoration', () => { + it('preserves unrelated padding longhands after an unframed capture', () => { + const style = { + paddingTop: '', + paddingRight: '', + paddingBottom: '', + paddingLeft: '12px', + } + const originalPadding = snapshotCapturePadding(style, false) + + style.paddingBottom = '48px' + restoreCapturePadding(style, originalPadding) + + assert.deepEqual(style, { + paddingTop: '', + paddingRight: '', + paddingBottom: '', + paddingLeft: '12px', + }) + }) + + it('restores every padding longhand after a framed capture', () => { + const style = { + paddingTop: '', + paddingRight: '', + paddingBottom: '', + paddingLeft: '12px', + } + const originalPadding = snapshotCapturePadding(style, true) + + style.paddingTop = '16px' + style.paddingRight = '40px' + style.paddingBottom = '48px' + style.paddingLeft = '40px' + restoreCapturePadding(style, originalPadding) + + assert.deepEqual(style, { + paddingTop: '', + paddingRight: '', + paddingBottom: '', + paddingLeft: '12px', + }) + }) +}) describe('resolveCaptureBoxSizing', () => { it('adds frame width without narrowing the captured content', () => { diff --git a/src/utils/captureLayout.ts b/src/utils/captureLayout.ts index fba2a99b..e67455d9 100644 --- a/src/utils/captureLayout.ts +++ b/src/utils/captureLayout.ts @@ -1,6 +1,37 @@ const DEFAULT_NARROWING_BASE_WIDTH = 525 const NARROWING_SCALE_FACTOR = 0.3 +interface CapturePaddingStyle { + paddingTop: string + paddingRight: string + paddingBottom: string + paddingLeft: string +} + +interface CapturePaddingSnapshot extends CapturePaddingStyle { + restoreAll: boolean +} + +export function snapshotCapturePadding(style: CapturePaddingStyle, captureFrame: boolean): CapturePaddingSnapshot { + return { + paddingTop: style.paddingTop, + paddingRight: style.paddingRight, + paddingBottom: style.paddingBottom, + paddingLeft: style.paddingLeft, + restoreAll: captureFrame, + } +} + +export function restoreCapturePadding(style: CapturePaddingStyle, snapshot: CapturePaddingSnapshot): void { + // 普通截图只改动底部水印留白;外框截图覆盖了整个 padding,才需要逐项恢复。 + if (snapshot.restoreAll) { + style.paddingTop = snapshot.paddingTop + style.paddingRight = snapshot.paddingRight + style.paddingLeft = snapshot.paddingLeft + } + style.paddingBottom = snapshot.paddingBottom +} + interface CaptureBoxSizingOptions { currentWidth: number progressiveNarrowing?: number | boolean