merge(dev): 走马灯滚出终点调整

This commit is contained in:
2026-08-03 17:52:18 +08:00
@@ -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<number> {
});
}
function measureTextWidth(selector: string, text: string): Promise<number> {
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 (
<View id={rootIdRef.current} className="store-detail-marquee">
<View className="store-detail-marquee-inner" style={innerStyle}>
<Text className="store-detail-marquee-text">{current}</Text>
<Text id={textIdRef.current} className="store-detail-marquee-text">
{current}
</Text>
</View>
</View>
);