From 7e3dc131adbfc032d2bac752ee19d275b4df04e9 Mon Sep 17 00:00:00 2001 From: jacy <18049821889@163.com> Date: Mon, 3 Aug 2026 17:52:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(mini-user):=20=E8=B5=B0=E9=A9=AC=E7=81=AF?= =?UTF-8?q?=E5=85=A8=E6=96=87=E6=BB=9A=E5=87=BA=E8=A7=86=E5=8F=A3=E5=90=8E?= =?UTF-8?q?=E5=86=8D=E5=A4=9A=E8=B5=B0=2010px?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../src/components/StoreRedeemMarquee.tsx | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/apps/mini-user/src/components/StoreRedeemMarquee.tsx b/apps/mini-user/src/components/StoreRedeemMarquee.tsx index f8f1de7..c6d6915 100644 --- a/apps/mini-user/src/components/StoreRedeemMarquee.tsx +++ b/apps/mini-user/src/components/StoreRedeemMarquee.tsx @@ -11,8 +11,16 @@ const MIN_FLY_MS = 2400; const PAUSE_MIN_MS = 1000; const PAUSE_MAX_MS = 5000; const TICK_MS = 16; -/** 飘动终点:left 停在此处(略向左溢出 10px) */ -const STOP_LEFT_PX = -10; +/** 全文滚出视口后,再向左多走 10px */ +const EXTRA_AFTER_EXIT_PX = 10; + +function estimateTextWidth(text: string): number { + let w = 0; + for (const ch of text) { + w += /[^\x00-\xff]/.test(ch) ? 12 : 7; + } + return Math.max(Math.ceil(w), 80); +} function randomPauseMs() { return PAUSE_MIN_MS + Math.floor(Math.random() * (PAUSE_MAX_MS - PAUSE_MIN_MS + 1)); @@ -50,6 +58,28 @@ function measureBoxWidth(selector: string, fallback: number): Promise { }); } +function measureTextWidth(selector: string, text: string): Promise { + const fallback = estimateTextWidth(text); + return new Promise((resolve) => { + Taro.nextTick(() => { + try { + const page = Taro.getCurrentInstance().page; + const query = page ? Taro.createSelectorQuery().in(page) : Taro.createSelectorQuery(); + query + .select(selector) + .boundingClientRect() + .exec((res) => { + const w = Number(res?.[0]?.width || 0); + if (w > 8 && w < fallback * 3) resolve(Math.ceil(w)); + else resolve(fallback); + }); + } catch { + resolve(fallback); + } + }); + }); +} + /** * 核销走马灯:单条从右向左位移飞出,间隔 1~5 秒随机再播下一条。 * @@ -68,6 +98,7 @@ export default function StoreRedeemMarquee({ lines }: StoreRedeemMarqueeProps) { ); const rootIdRef = useRef(`smr${Math.random().toString(36).slice(2, 10)}`); + const textIdRef = useRef(`smt${Math.random().toString(36).slice(2, 10)}`); const indexRef = useRef(0); const boxWidthRef = useRef(getBoxWidthFallback()); const itemsKey = items.join('\n'); @@ -128,16 +159,22 @@ export default function StoreRedeemMarquee({ lines }: StoreRedeemMarqueeProps) { while (!cancelled && items.length) { const idx = indexRef.current % items.length; + const text = items[idx]; const box = boxWidthRef.current; setDisplayIndex(idx); const from = box; - const to = STOP_LEFT_PX; + setLeftPx(from); + await sleep(48); + if (cancelled) break; + + const textW = await measureTextWidth(`#${textIdRef.current}`, text); + // 全文 left 边缘移出容器左边界后再走 10px + const to = -(textW + EXTRA_AFTER_EXIT_PX); const distance = from - to; const durationMs = Math.max(MIN_FLY_MS, Math.round((distance / FLY_SPEED) * 1000)); - setLeftPx(from); await sleep(32); if (cancelled) break; @@ -169,7 +206,9 @@ export default function StoreRedeemMarquee({ lines }: StoreRedeemMarqueeProps) { return ( - {current} + + {current} + );