This commit is contained in:
2026-09-24 16:25:22 +08:00
commit 7428184f01
1198 changed files with 314515 additions and 0 deletions
+391
View File
@@ -0,0 +1,391 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>uvue 动效改写验证 · 红点呼吸 / 扫描线 / 手风琴</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 32px 24px 64px;
background: #F3F4F6;
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
color: #1F2937;
}
.wrap {
max-width: 1040px;
margin: 0 auto;
}
h1 {
font-size: 22px;
margin: 0 0 6px;
}
.sub {
font-size: 13px;
color: #6B7280;
margin: 0 0 8px;
line-height: 1.7;
}
.warn {
background: #FFFBEB;
border: 1px solid #FDE68A;
color: #92400E;
border-radius: 12px;
padding: 12px 16px;
font-size: 13px;
line-height: 1.7;
margin-bottom: 26px;
}
.grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
flex: 1 1 300px;
min-width: 300px;
background: #FFF;
border: 1px solid #E5E7EB;
border-radius: 16px;
padding: 18px 20px 20px;
}
.card h2 {
font-size: 15px;
margin: 0 0 4px;
}
.src {
font-size: 11px;
color: #9CA3AF;
font-family: ui-monospace, Menlo, Consolas, monospace;
margin: 0 0 16px;
}
.stage {
height: 210px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
/* ---- 1. 红点 ---- */
.evt-card {
width: 210px;
background: #FFFBFB;
border: 1px solid #FECACA;
border-radius: 13px;
padding: 12px 13px;
}
.evt-top {
display: flex;
align-items: center;
}
.evt-dot {
width: 8px;
height: 8px;
border-radius: 4px;
margin: 0 8px;
background-color: #DC2626;
}
.evt-name {
flex: 1;
font-size: 15px;
font-weight: 700;
}
.pri {
background: #DC2626;
color: #FFF;
font-size: 11px;
font-weight: 700;
border-radius: 6px;
padding: 2px 8px;
}
/* ---- 2. 扫描线 ---- */
.sc-box {
width: 100%;
height: 178px;
background: #0F172A;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.sc-frame {
width: 93px;
height: 93px;
position: relative;
}
.cf {
position: absolute;
width: 13px;
height: 13px;
border: 3px solid #10B981;
border-radius: 4px;
}
.cf-tl {
top: 0;
left: 0;
border-right-width: 0;
border-bottom-width: 0;
}
.cf-tr {
top: 0;
right: 0;
border-left-width: 0;
border-bottom-width: 0;
}
.cf-bl {
bottom: 0;
left: 0;
border-right-width: 0;
border-top-width: 0;
}
.cf-br {
bottom: 0;
right: 0;
border-left-width: 0;
border-top-width: 0;
}
.sc-line {
position: absolute;
left: 8.4px;
right: 8.4px;
height: 2px;
background: #10B981;
box-shadow: 0 0 8px rgba(16, 185, 129, .9);
}
.sc-tip {
position: absolute;
bottom: 12px;
left: 0;
right: 0;
text-align: center;
font-size: 11px;
color: rgba(255, 255, 255, .78);
}
/* ---- 3. 手风琴 ---- */
.qa-card {
width: 250px;
background: #FFF;
border: 1px solid #E5E7EB;
border-left: 4px solid #2563EB;
border-radius: 10px;
padding: 11px 12px;
box-shadow: 0 2px 10px rgba(15, 23, 42, .06);
}
.qa-stem {
font-size: 13px;
font-weight: 700;
}
.qa-fold {
margin-top: 8px;
display: flex;
justify-content: flex-end;
}
.qa-btn {
font-size: 12px;
color: #2563EB;
font-weight: 700;
cursor: pointer;
user-select: none;
}
.qa-analysis {
margin-top: 10px;
padding: 9px 10px;
border-radius: 9px;
background: #F9FAFB;
font-size: 12px;
color: #6B7280;
line-height: 1.6;
}
.readout {
margin-top: 12px;
font-size: 11px;
color: #9CA3AF;
font-family: ui-monospace, Menlo, Consolas, monospace;
}
</style>
</head>
<body>
<div class="wrap">
<h1>uvue App 端动效改写 · 效果验证</h1>
<p class="sub">下方三个动效与 App 里 <b>完全相同</b> 的算法在跑(定时器逐帧推进 → 下发内联 style),
只是把 rpx 折算成 px1rpx = 0.5px @375)。</p>
<div class="warn">
<b>背景</b>App 端 uvue 的 CSS 编译器不接受 <code>@keyframes</code>0%/75%/from/to 选择器直接报
ERROR)与 <code>animation</code> 属性,
因此这 3 处动效已全部改为 <code>setInterval</code> + <code>ref</code> 驱动内联样式的等价实现。
</div>
<div class="grid">
<!-- 1 -->
<div class="card">
<h2>① 待接收红点「呼吸」</h2>
<p class="src">pages/event/index.uvue · evtPulse</p>
<div class="stage" style="background:#F9FAFB">
<div class="evt-card">
<div class="evt-top">
<div class="evt-dot" id="dot"></div>
<span class="evt-name">车祸伤 · 多人受伤</span>
<span class="pri">P0</span>
</div>
</div>
</div>
<div class="readout" id="dotOut">半径 0rpx · 透明度 0.55</div>
</div>
<!-- 2 -->
<div class="card">
<h2>② 取景框扫描线</h2>
<p class="src">pages/warehouse/scan.uvue · hrScanMove</p>
<div class="stage">
<div class="sc-box">
<div class="sc-frame">
<div class="cf cf-tl"></div>
<div class="cf cf-tr"></div>
<div class="cf cf-bl"></div>
<div class="cf cf-br"></div>
<div class="sc-line" id="line"></div>
</div>
<div class="sc-tip">将条码对准框内 · 自动识别</div>
</div>
</div>
<div class="readout" id="lineOut">top 60rpx → 313rpx · 32 帧 × 68ms = 2.18s</div>
</div>
<!-- 3 -->
<div class="card">
<h2>③ 手风琴展开入场</h2>
<p class="src">pages/study/center.uvue · qa-acc-in</p>
<div class="stage" style="background:#F9FAFB">
<div class="qa-card">
<div class="qa-stem">成人胸外按压的深度应为?</div>
<div class="qa-fold"><span class="qa-btn" id="accBtn">点击展开解析</span></div>
<div id="accHost"></div>
</div>
</div>
<div class="readout" id="accOut">opacity 0 → 1 · translateY -16rpx → 0 · 240ms</div>
</div>
</div>
</div>
<script>
/* ============ ① 红点呼吸:与 pages/event/index.uvue 完全同算法 ============ */
const PULSE_FRAMES = 25
const PULSE_RAMP = 19
let pulseF = 0
const dotEl = document.getElementById('dot')
const dotOut = document.getElementById('dotOut')
/* 改写前的 CSS 版本,用作「应该长什么样」的参照 */
const RING_MAX_PX = 16 * 0.5 // 16rpx
function renderPulse() {
const i = pulseF
let r = 0, a = 0
if (i > PULSE_RAMP) { r = 0; a = 0 } else {
const k = i / PULSE_RAMP
r = Math.round(k * 16)
a = Math.round(55 * (1 - k))
}
dotEl.style.boxShadow = '0 0 0 ' + (r * 0.5).toFixed(1) + 'px rgba(220,38,38,0.' + a + ')'
dotOut.textContent = '半径 ' + r + 'rpx · 透明度 0.' + a + ' · 第 ' + i + '/25 帧'
const nf = pulseF + 1
pulseF = nf >= PULSE_FRAMES ? 0 : nf
}
setInterval(renderPulse, 68)
renderPulse()
/* ============ ② 扫描线:与 pages/warehouse/scan.uvue 完全同算法 ============ */
const LASER_MIN = 60, LASER_SPAN = 253
let laserT = 0.0
const lineEl = document.getElementById('line')
const lineOut = document.getElementById('lineOut')
function renderLaser() {
laserT = laserT + 0.03125
if (laserT > 1) { laserT = laserT - 1 }
const k = laserT < 0.5 ? laserT * 2 : (1 - laserT) * 2
const top = Math.round(LASER_MIN + k * LASER_SPAN)
lineEl.style.top = (top * 0.5).toFixed(1) + 'px'
lineOut.textContent = 'top ' + top + 'rpx (区间 60 → 313) · 32 帧 × 68ms = 2.18s'
}
setInterval(renderLaser, 68)
renderLaser()
/* ============ ③ 手风琴:与 pages/study/center.uvue 完全同算法 ============ */
let accIdx = -1, accT = 1, accTimer = 0, accOpen = false
const accHost = document.getElementById('accHost')
const accBtn = document.getElementById('accBtn')
const accOut = document.getElementById('accOut')
function stopAcc() {
if (accTimer != 0) { clearInterval(accTimer); accTimer = 0 }
}
function runAcc() {
stopAcc()
accIdx = 0
accT = 0
accTimer = setInterval(() => {
const t = accT + 0.16
if (t >= 1) { accT = 1; stopAcc(); renderAcc(); return }
accT = t
renderAcc()
}, 30)
}
function renderAcc() {
if (!accOpen) { accHost.innerHTML = ''; accOut.textContent = '已收起'; return }
if (accT >= 1) {
accHost.innerHTML = '<div class="qa-analysis">按压深度 5~6 cm,频率 100~120 次/分;每次按压后让胸廓完全回弹。</div>'
accOut.textContent = 'opacity 1 · translateY 0 · 动画完成'
return
}
const t = accT
const y = Math.round(-16 * (1 - t))
accHost.innerHTML = '<div class="qa-analysis" style="opacity:' + t +
';transform:translateY(' + (y * 0.5).toFixed(1) + 'px)">按压深度 5~6 cm,频率 100~120 次/分;每次按压后让胸廓完全回弹。</div>'
accOut.textContent = 'opacity ' + t.toFixed(2) + ' · translateY ' + y + 'rpx'
}
accBtn.addEventListener('click', () => {
accOpen = !accOpen
accBtn.textContent = accOpen ? '收起解析' : '点击展开解析'
if (accOpen) { runAcc() } else { stopAcc(); accIdx = -1; accT = 1; renderAcc() }
})
</script>
</body>
</html>