1. 弹幕功能
2. 点赞 3. 导航引导 4. ai弹幕、审核
This commit is contained in:
@@ -16,15 +16,19 @@ import { ref } from 'vue'
|
||||
const hearts = ref([])
|
||||
let uid = 0
|
||||
|
||||
/** 单次最多同时排队的爱心数,避免超高点赞拖垮渲染 */
|
||||
const MAX_BURST = 80
|
||||
|
||||
const burst = (count = 3) => {
|
||||
const n = Math.max(1, Math.min(3, count))
|
||||
const n = Math.max(0, Math.min(MAX_BURST, Math.floor(Number(count) || 0)))
|
||||
if (!n) return
|
||||
for (let i = 0; i < n; i += 1) {
|
||||
const id = ++uid
|
||||
const left = 12 + Math.random() * 48
|
||||
const drift = (Math.random() - 0.5) * 36
|
||||
const duration = 1.2 + Math.random() * 0.6
|
||||
const delay = i * 0.08
|
||||
const scale = 0.85 + Math.random() * 0.45
|
||||
const left = 10 + Math.random() * 200
|
||||
const drift = (Math.random() - 0.5) * 90
|
||||
const duration = 1.25 + Math.random() * 0.7
|
||||
const delay = i * 0.045
|
||||
const scale = 0.8 + Math.random() * 0.55
|
||||
hearts.value.push({
|
||||
id,
|
||||
style: {
|
||||
@@ -50,15 +54,15 @@ defineExpose({ burst })
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 120px;
|
||||
height: 55vh;
|
||||
width: min(46vw, 280px);
|
||||
height: 58vh;
|
||||
z-index: 45;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
.like-burst-heart {
|
||||
position: absolute;
|
||||
bottom: 24px;
|
||||
bottom: 28px;
|
||||
color: #f472b6;
|
||||
font-size: 22px;
|
||||
line-height: 1;
|
||||
@@ -78,7 +82,7 @@ defineExpose({ burst })
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate3d(var(--drift, 0px), -42vh, 0) scale(var(--scale, 1));
|
||||
transform: translate3d(var(--drift, 0px), -46vh, 0) scale(var(--scale, 1));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -85,19 +85,30 @@
|
||||
</div>
|
||||
|
||||
<!-- 底部互动区:点赞 / 填写 / 评论条 -->
|
||||
<div class="action-dock">
|
||||
<div
|
||||
class="action-dock"
|
||||
@touchstart.stop
|
||||
@touchmove.stop
|
||||
@touchend.stop
|
||||
@mousedown.stop
|
||||
@click.stop
|
||||
>
|
||||
<!-- 右下点赞邻域隐形遮罩:吞掉穿透到页面的触摸,避免误触预览/暂停 -->
|
||||
<div class="like-side-shield" aria-hidden="true" />
|
||||
<div class="action-dock-row">
|
||||
<button
|
||||
type="button"
|
||||
class="action-pill like-fab"
|
||||
:class="{ liked: likePulse, busy: likeBusy }"
|
||||
:disabled="likeBusy"
|
||||
title="点赞"
|
||||
@click="handleLike"
|
||||
>
|
||||
<i class="fa-heart like-icon" :class="likePulse ? 'fa-solid' : 'fa-regular'"></i>
|
||||
<span class="like-count">{{ likeCount }}</span>
|
||||
</button>
|
||||
<div class="like-hit-zone">
|
||||
<button
|
||||
type="button"
|
||||
class="action-pill like-fab"
|
||||
:class="{ liked: likePulse, busy: likeBusy }"
|
||||
:disabled="likeBusy"
|
||||
title="点赞"
|
||||
@click="handleLike"
|
||||
>
|
||||
<i class="fa-heart like-icon" :class="likePulse ? 'fa-solid' : 'fa-regular'"></i>
|
||||
<span class="like-count">{{ likeCount }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="action-pill action-rsvp"
|
||||
@@ -105,7 +116,6 @@
|
||||
@click="showTrackList = false; isDrawerOpen = true"
|
||||
>
|
||||
<img src="https://api.iconify.design/lucide:clipboard-pen.svg?color=%23a88c6b" class="action-pill-icon" alt="" />
|
||||
<!-- <span>填写</span>-->
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
@@ -830,6 +840,11 @@ const completeIntro = () => {
|
||||
scrollPageToTop()
|
||||
showIntro.value = false
|
||||
introOpening.value = false
|
||||
if (pendingLikeBurst > 0) {
|
||||
const n = pendingLikeBurst
|
||||
pendingLikeBurst = 0
|
||||
nextTick(() => likeBurstRef.value?.burst(n))
|
||||
}
|
||||
scheduleAutoScrollStart()
|
||||
}
|
||||
|
||||
@@ -953,10 +968,17 @@ const handleSubmitBlessing = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
let pendingLikeBurst = 0
|
||||
|
||||
const loadLikeStatus = async () => {
|
||||
try {
|
||||
const res = await getLikeStatus(getClientId())
|
||||
likeCount.value = Number(res.data?.count) || 0
|
||||
const count = Number(res.data?.count) || 0
|
||||
likeCount.value = count
|
||||
if (count <= 0) return
|
||||
// 揭幕中则等结束后再播,避免帘幕后白播
|
||||
if (showIntro.value) pendingLikeBurst = count
|
||||
else nextTick(() => likeBurstRef.value?.burst(count))
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
@@ -1104,13 +1126,36 @@ watch(
|
||||
pointer-events: none;
|
||||
}
|
||||
.action-dock-row {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
.action-dock-row > * { pointer-events: auto; }
|
||||
/* 右下点赞/填写周围扩大命中与遮罩,防止点到下方图片 */
|
||||
.like-side-shield {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: min(52vw, 220px);
|
||||
height: calc(132px + env(safe-area-inset-bottom, 0px));
|
||||
pointer-events: auto;
|
||||
z-index: 1;
|
||||
background: transparent;
|
||||
}
|
||||
.like-hit-zone {
|
||||
position: relative;
|
||||
pointer-events: auto;
|
||||
padding: 22px 26px 28px;
|
||||
margin: -22px -26px -28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 3;
|
||||
}
|
||||
.action-pill {
|
||||
min-width: 52px;
|
||||
min-height: 52px;
|
||||
@@ -1155,6 +1200,8 @@ watch(
|
||||
}
|
||||
.like-fab.liked .like-count { color: #f472b6; font-weight: 600; }
|
||||
.action-comment {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
pointer-events: auto;
|
||||
width: 100%;
|
||||
min-height: 48px;
|
||||
|
||||
Reference in New Issue
Block a user