1. 礼物特效
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<canvas ref="canvasRef" class="gift-effect-canvas" aria-hidden="true" />
|
||||
<Teleport to="body">
|
||||
<canvas ref="canvasRef" class="gift-effect-canvas" aria-hidden="true" />
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -252,12 +254,22 @@ function resizeCanvas() {
|
||||
const canvas = canvasRef.value
|
||||
if (!canvas) return
|
||||
dpr = Math.min(window.devicePixelRatio || 1, DPR_CAP)
|
||||
// iOS:优先用 visualViewport,避免地址栏伸缩导致尺寸错乱
|
||||
const vv = typeof window !== 'undefined' ? window.visualViewport : null
|
||||
const cssW = Math.max(1, Math.floor((vv && vv.width) || window.innerWidth || canvas.clientWidth || 1))
|
||||
const cssH = Math.max(1, Math.floor((vv && vv.height) || window.innerHeight || canvas.clientHeight || 1))
|
||||
// 用布局视口铺满全屏。iOS visualViewport 常窄于整屏且有 offset,
|
||||
// 再叠 wrapper overflow 裁切,会出现「只盖住左侧一块」的灰幕。
|
||||
const cssW = Math.max(
|
||||
1,
|
||||
Math.floor(window.innerWidth || 0),
|
||||
Math.floor(document.documentElement?.clientWidth || 0),
|
||||
)
|
||||
const cssH = Math.max(
|
||||
1,
|
||||
Math.floor(window.innerHeight || 0),
|
||||
Math.floor(document.documentElement?.clientHeight || 0),
|
||||
)
|
||||
W = cssW
|
||||
H = cssH
|
||||
canvas.style.left = '0px'
|
||||
canvas.style.top = '0px'
|
||||
canvas.style.width = `${cssW}px`
|
||||
canvas.style.height = `${cssH}px`
|
||||
canvas.style.writingMode = 'horizontal-tb'
|
||||
@@ -819,7 +831,7 @@ function playOne(item) {
|
||||
const payload = normalizePlayItem(item)
|
||||
if (!payload) return 0
|
||||
const { giftType, name, count } = payload
|
||||
if (!W || !H) resizeCanvas()
|
||||
resizeCanvas()
|
||||
clearVisuals()
|
||||
const now = performance.now()
|
||||
const style = GIFT_STYLE[giftType]
|
||||
@@ -1340,7 +1352,6 @@ onMounted(() => {
|
||||
}
|
||||
window.addEventListener('resize', onResize)
|
||||
window.visualViewport?.addEventListener('resize', onResize)
|
||||
window.visualViewport?.addEventListener('scroll', onResize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -1353,7 +1364,6 @@ onUnmounted(() => {
|
||||
if (rafId) cancelAnimationFrame(rafId)
|
||||
window.removeEventListener('resize', onResize)
|
||||
window.visualViewport?.removeEventListener('resize', onResize)
|
||||
window.visualViewport?.removeEventListener('scroll', onResize)
|
||||
texts = []
|
||||
particles = []
|
||||
rings = []
|
||||
@@ -1379,9 +1389,11 @@ defineExpose({ play, playSequence, clear: clearAll, stop: clearAll })
|
||||
<style scoped>
|
||||
.gift-effect-canvas {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
width: 100dvw;
|
||||
height: 100%;
|
||||
height: 100dvh;
|
||||
z-index: 46;
|
||||
@@ -1391,9 +1403,9 @@ defineExpose({ play, playSequence, clear: clearAll, stop: clearAll })
|
||||
text-orientation: mixed;
|
||||
direction: ltr;
|
||||
white-space: nowrap;
|
||||
/* iOS:独立合成层,避免和左侧点赞 canvas / transform 滚动打架 */
|
||||
transform: translateZ(0);
|
||||
-webkit-transform: translateZ(0);
|
||||
/* 独立合成层;挂到 body 后不再受请柬 wrapper overflow 裁切 */
|
||||
transform: translate3d(0, 0, 0);
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user