hookehuyr

feat(弹幕组件): 添加原生弹幕组件并集成到排行榜页面

- 新增 NativeDanmuComponent 原生弹幕组件,支持多轨道弹幕展示
- 在家庭排行榜页面集成弹幕功能,展示助力榜内容
- 调整排行榜卡片布局和样式,优化助力码按钮位置
- 添加弹幕点击和悬停事件处理逻辑
......@@ -13,6 +13,7 @@ declare module 'vue' {
BottomNav: typeof import('./src/components/BottomNav.vue')['default']
FamilyAlbum: typeof import('./src/components/FamilyAlbum.vue')['default']
GlassCard: typeof import('./src/components/GlassCard.vue')['default']
NativeDanmuComponent: typeof import('./src/components/NativeDanmuComponent.vue')['default']
NavBar: typeof import('./src/components/navBar.vue')['default']
NumberRoll: typeof import('./src/components/NumberRoll.vue')['default']
NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet']
......
<template>
<view class="native-danmu-container">
<!-- 弹幕显示区域 -->
<view
class="danmu-display-area"
:style="{ height: containerHeight + 'rpx' }"
>
<!-- 弹幕轨道 -->
<view
v-for="(track, trackIndex) in tracks"
:key="trackIndex"
class="danmu-track"
:style="{ top: trackIndex * trackHeight + 'rpx', height: trackHeight + 'rpx' }"
>
<!-- 轨道中的弹幕 -->
<view
v-for="danmu in track.danmus"
:key="danmu.id"
class="danmu-item"
:style="getDanmuStyle(danmu, trackIndex)"
@tap="handleDanmuClick(danmu)"
>
<!-- 弹幕内容 -->
<view class="danmu-content">
<!-- 头像 -->
<view class="danmu-avatar-container">
<image
:src="danmu.data.avatar"
class="danmu-avatar"
mode="aspectFill"
/>
</view>
<!-- 信息区域 -->
<view class="danmu-info">
<!-- 标题行 -->
<view class="danmu-title-row">
<text class="family-name">{{ danmu.data.familyName }}</text>
</view>
<!-- 介绍 -->
<text class="family-intro">{{ danmu.data.familyIntro }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
import Taro from '@tarojs/taro'
// Props
const props = defineProps({
// 弹幕容器高度
containerHeight: {
type: Number,
default: 400
},
// 是否显示控制面板
showControls: {
type: Boolean,
default: true
},
// 自定义弹幕数据
customComments: {
type: Array,
default: () => []
},
// 弹幕速度 (rpx/s)
danmuSpeed: {
type: Number,
default: 120 // 提高默认速度,让弹幕移动更流畅
},
// 轨道数量
trackCount: {
type: Number,
default: 6 // 适当减少轨道数量,确保有足够间距
}
})
// Emits
const emit = defineEmits(['danmu-click', 'danmu-hover'])
// 响应式数据
const isPlaying = ref(false)
const danmuId = ref(0)
const trackHeight = ref(110) // 适配最多3行文字显示,确保弹幕之间有足够间距
const animationTimers = ref(new Map()) // 存储动画定时器
// 轨道系统
const tracks = reactive(
Array.from({ length: props.trackCount }, (_, index) => ({
id: index,
danmus: [],
lastDanmuTime: 0
}))
)
// Mock 数据 - 家庭弹幕内容
const baseFamilyData = {
familyName: '幸福之家',
familyIntro: '7口之家,父母健康,有儿有女,孩子活泼可爱,我们工作顺利',
avatar: 'https://cdn.ipadbiz.cn/lls_prog/images/%E5%85%A8%E5%AE%B6%E7%A6%8F3_%E5%89%AF%E6%9C%AC.jpg?imageMogr2/strip/quality/60',
}
// 生成1000条相同的弹幕数据
const mockFamilyDanmus = Array.from({ length: 1000 }, (_, index) => ({
id: (index + 1).toString(),
...baseFamilyData
}))
// 获取弹幕样式
const getDanmuStyle = (danmu, trackIndex) => {
// 计算垂直位置,确保每个轨道有明确的垂直间距
const topPosition = trackIndex * (trackHeight.value + 15) // 轨道间增加15rpx间距,适配3行文字
return {
transform: `translateX(${danmu.x}rpx)`,
transition: danmu.isMoving ? `transform ${danmu.duration}ms linear` : 'none',
opacity: danmu.opacity || 1,
// 明确设置垂直位置
position: 'absolute',
left: 0,
top: `${topPosition}rpx`,
zIndex: 10,
// 添加硬件加速
willChange: 'transform'
}
}
// 检查轨道中是否有足够空间放置新弹幕
const checkTrackSpace = (track, danmuWidth = 350) => {
const now = Date.now()
// 如果轨道为空,可以直接放置
if (track.danmus.length === 0) {
return true
}
// 检查最后一个弹幕的位置和时间
const lastDanmu = track.danmus[track.danmus.length - 1]
const timeSinceLastDanmu = now - track.lastDanmuTime
// 更精确的位置计算
const elapsedTime = now - lastDanmu.startTime
const totalDistance = 750 + danmuWidth + 100 // 总移动距离
const moveDistance = Math.min((elapsedTime / lastDanmu.duration) * totalDistance, totalDistance)
const lastDanmuCurrentX = 750 - moveDistance
// 调整安全间距,考虑3行文字的情况
const minSafeDistance = danmuWidth * 0.4 // 增加到40%,为3行文字预留更多空间
const safeDistance = danmuWidth + minSafeDistance // 弹幕宽度 + 40%弹幕长度作为间距
const hasEnoughSpace = lastDanmuCurrentX < (750 - safeDistance)
// 适当增加时间间隔,确保3行文字弹幕有足够的显示时间
const minTimeInterval = 1800 // 从1600ms增加到1800ms,为3行文字预留更多时间
const hasEnoughTime = timeSinceLastDanmu >= minTimeInterval
// 双重检查:时间和空间都满足才允许放置
return hasEnoughTime && hasEnoughSpace
}
// 找到可用的轨道 - 随机选择而非按顺序
const findAvailableTrack = () => {
// 过滤出有足够空间的轨道
const availableTracks = tracks.filter(track => checkTrackSpace(track))
// 如果没有可用轨道,返回null
if (availableTracks.length === 0) {
return null
}
// 从可用轨道中随机选择一个
const randomIndex = Math.floor(Math.random() * availableTracks.length)
return availableTracks[randomIndex]
}
// 创建弹幕对象
const createDanmu = (data) => {
const id = `danmu_${danmuId.value++}`
const containerWidth = 750 // 小程序默认宽度
const danmuWidth = 350 // 弹幕宽度
const extraDistance = 100 // 额外移动距离,确保完全消失
return {
id,
data,
x: containerWidth, // 从右侧开始
isMoving: false,
opacity: 1,
duration: ((containerWidth + danmuWidth + extraDistance) / (props.danmuSpeed * 0.6)) * 1000, // 减慢速度,让弹幕在屏幕上停留更久
startTime: Date.now()
}
}
// 添加弹幕到轨道
const addDanmuToTrack = (danmu) => {
const track = findAvailableTrack()
if (!track) return false
track.danmus.push(danmu)
track.lastDanmuTime = Date.now()
// 启动弹幕动画
nextTick(() => {
startDanmuAnimation(danmu, track)
})
return true
}
// 启动弹幕动画
const startDanmuAnimation = (danmu, track) => {
if (!isPlaying.value) return
// 清除之前的定时器(如果存在)
if (animationTimers.value.has(danmu.id)) {
clearTimeout(animationTimers.value.get(danmu.id))
animationTimers.value.delete(danmu.id)
}
// 设置动画 - 从右侧移动到左侧屏幕外
danmu.isMoving = true
// 使用 nextTick 确保 DOM 更新后再启动动画
nextTick(() => {
// 移动到左侧屏幕外,确保弹幕完全消失
danmu.x = -(450) // 移动距离 = 弹幕宽度(350) + 额外距离(100)
})
// 监听动画结束事件,实现循环
const timer = setTimeout(() => {
// 动画结束后,重置弹幕位置到右侧,开始新的循环
resetDanmuForLoop(danmu, track)
}, danmu.duration)
animationTimers.value.set(danmu.id, timer)
}
// 重置弹幕位置实现循环
const resetDanmuForLoop = (danmu, track) => {
if (!isPlaying.value) return
// 立即停止当前动画
danmu.isMoving = false
// 使用 nextTick 确保 DOM 更新
nextTick(() => {
// 重置弹幕位置到右侧
danmu.x = 750 // 回到右侧起始位置
// 短暂延迟后重新开始动画
setTimeout(() => {
if (isPlaying.value) {
startDanmuAnimation(danmu, track)
}
}, 50) // 减少延迟时间
})
}
// 从轨道移除弹幕
const removeDanmuFromTrack = (danmu, track) => {
const index = track.danmus.findIndex(d => d.id === danmu.id)
if (index > -1) {
track.danmus.splice(index, 1)
}
}
// 发送弹幕
const sendDanmu = (data) => {
if (!isPlaying.value) return
const danmu = createDanmu(data)
addDanmuToTrack(danmu)
}
// 当前弹幕索引,用于顺序显示
let currentDanmuIndex = 0
// 发送顺序弹幕
const sendSequentialDanmu = () => {
// 按顺序获取弹幕数据
const danmuData = mockFamilyDanmus[currentDanmuIndex % mockFamilyDanmus.length]
sendDanmu(danmuData)
// 更新索引,循环使用
currentDanmuIndex++
}
// 自动发送弹幕
let autoSendTimer = null
const startAutoSend = () => {
if (autoSendTimer) return
const sendNext = () => {
if (isPlaying.value) {
// 移除弹幕数量限制,直接发送弹幕
sendSequentialDanmu()
}
// 优化发送间隔,在保持合理间距的同时增加密度
autoSendTimer = setTimeout(sendNext, 1000 + Math.random() * 600) // 1.0-1.6秒随机间隔,适度增加发送频率
}
sendNext()
}
const stopAutoSend = () => {
if (autoSendTimer) {
clearTimeout(autoSendTimer)
autoSendTimer = null
}
}
// 暂停/播放弹幕
const toggleDanmu = () => {
isPlaying.value = !isPlaying.value
if (isPlaying.value) {
// 恢复播放时,重新启动所有弹幕的动画
tracks.forEach(track => {
track.danmus.forEach(danmu => {
if (!danmu.isMoving) {
startDanmuAnimation(danmu, track)
}
})
})
startAutoSend()
} else {
// 暂停时,停止自动发送但保持弹幕在当前位置
stopAutoSend()
}
}
// 清空所有弹幕
const clearDanmu = () => {
// 清除所有动画定时器
animationTimers.value.forEach(timer => clearTimeout(timer))
animationTimers.value.clear()
// 清空所有轨道的弹幕
tracks.forEach(track => {
track.danmus = []
track.lastDanmuTime = 0
})
}
// 处理弹幕点击
const handleDanmuClick = (danmu) => {
emit('danmu-click', danmu.data)
Taro.showToast({
title: `点击了${danmu.data.familyName}`,
icon: 'none',
duration: 2000
})
}
// 暴露方法给父组件
defineExpose({
toggleDanmu,
clearDanmu,
sendCustomDanmu: sendDanmu
})
// 生命周期
onMounted(() => {
// 自动开始播放并发送初始弹幕
isPlaying.value = true
// 页面加载后,优化初始弹幕发送,保持合理间距和密度
setTimeout(() => {
for (let i = 0; i < 4; i++) { // 适度增加初始弹幕数量
setTimeout(() => {
sendSequentialDanmu()
}, i * 800) // 调整发送间隔到0.8秒,平衡密度和间距
}
}, 400) // 减少初始延迟
// 启动自动发送
startAutoSend()
})
onUnmounted(() => {
stopAutoSend()
clearDanmu()
})
</script>
<style >
.native-danmu-container {
width: 100%;
position: relative;
}
.danmu-display-area {
width: 100%;
/* background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); */
/* border-radius: 20rpx; */
position: relative;
overflow: hidden;
/* box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1); */
}
.danmu-track {
position: absolute;
width: 100%;
left: 0;
pointer-events: none;
}
.danmu-item {
position: absolute;
top: 50%;
transform: translateY(-50%);
pointer-events: auto;
z-index: 10;
right: 0; /* 从右侧开始 */
}
.danmu-content {
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.65);
border-radius: 30rpx;
padding: 16rpx 20rpx;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
backdrop-filter: blur(12rpx);
border: 2rpx solid rgba(255, 255, 255, 0.4);
max-width: 350rpx;
min-width: 300rpx;
margin: 8rpx 0;
transition: all 0.3s ease;
}
.danmu-avatar-container {
flex-shrink: 0;
margin-right: 16rpx;
position: relative;
}
.danmu-avatar {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
border: 3rpx solid #fff;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
}
.danmu-avatar-container::after {
content: '';
position: absolute;
top: -2rpx;
left: -2rpx;
right: -2rpx;
bottom: -2rpx;
border-radius: 50%;
background: linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4);
z-index: -1;
animation: rotate 3s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.danmu-info {
flex: 1;
min-width: 0;
}
.danmu-title-row {
display: flex;
align-items: center;
margin-bottom: 6rpx;
}
.family-name {
font-weight: 700;
color: #1a202c;
font-size: 28rpx;
margin-right: 12rpx;
flex-shrink: 0;
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.1);
}
.member-badge {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
padding: 4rpx 12rpx;
border-radius: 16rpx;
font-size: 20rpx;
font-weight: 600;
flex-shrink: 0;
box-shadow: 0 2rpx 8rpx rgba(102, 126, 234, 0.3);
}
.family-intro {
color: #4a5568;
font-size: 24rpx;
display: -webkit-box;
margin-bottom: 6rpx;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-height: 1.4;
font-weight: 500;
}
.danmu-bottom-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.family-motto {
color: #2d3748;
font-size: 22rpx;
font-style: italic;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 12rpx;
opacity: 0.8;
}
.steps-badge {
background: linear-gradient(45deg, #48bb78, #38a169);
color: white;
padding: 4rpx 12rpx;
border-radius: 14rpx;
font-size: 20rpx;
font-weight: 600;
flex-shrink: 0;
box-shadow: 0 2rpx 8rpx rgba(72, 187, 120, 0.3);
}
.danmu-controls {
display: flex;
justify-content: center;
gap: 20rpx;
margin-top: 20rpx;
padding: 0 20rpx;
}
.control-btn {
flex: 1;
max-width: 200rpx;
height: 60rpx;
border-radius: 30rpx;
font-size: 24rpx;
}
/* 弹幕动画效果 */
.danmu-moving {
transition-timing-function: linear;
transition-property: transform;
}
/* 弹幕项基础样式 */
.danmu-item {
position: absolute;
z-index: 10;
will-change: transform;
backface-visibility: hidden;
transform-style: preserve-3d;
left: 0;
top: 0;
width: auto;
height: auto;
}
/* 悬停效果 */
.danmu-item:active .danmu-content {
transform: scale(0.98);
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.18);
transition: all 0.2s ease;
}
.danmu-content:hover {
transform: translateY(-2rpx);
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.16);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.danmu-content {
max-width: 300rpx;
min-width: 240rpx;
padding: 10rpx 16rpx;
}
.danmu-avatar {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
}
.family-name {
font-size: 24rpx;
}
.family-intro {
font-size: 20rpx;
}
}
</style>
<!--
* @Date: 2025-01-09 00:00:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-10-28 13:33:56
* @LastEditTime: 2025-10-28 16:24:46
* @FilePath: /lls_program/src/components/RankingCard.vue
* @Description: 排行榜卡片组件
-->
<template>
<view class="ranking-card bg-blue-500 bg-opacity-50">
<!-- 卡片头部 -->
<view class="card-header">
<view class="card-header" style="margin: 40rpx;">
<view class="card-title flex items-center">
<IconFont size="20" name="https://cdn.ipadbiz.cn/lls_prog/icon/%E5%A5%96%E6%9D%AF.png" />
<text class="ml-2">家庭步数总榜</text>
......@@ -17,7 +17,7 @@
</view>
<!-- 顶部导航 -->
<view class="nav-tabs">
<view class="nav-tabs" style="margin: 40rpx;">
<!-- 滑动指示器 -->
<view
class="tab-indicator"
......@@ -39,12 +39,12 @@
</view>
<!-- 排行榜内容 -->
<view class="rank-content" :class="{ 'content-switching': isContentSwitching }">
<view class="rank-content" :class="{ 'content-switching': isContentSwitching }" style="margin: 40rpx;">
<!-- 排行榜日期 -->
<view class="rank-date relative">
<!-- <view class="flex items-center justify-center"><text class="mr-2">截止昨日</text>{{ currentDate }}<text v-if="activeTab !== 'shanghai'" class="ml-2">排名</text><IconFont name="ask" size="16" class="ml-2" @click="handleRankAskClick"></IconFont></view> -->
<view class="flex items-center justify-center"><text class="mr-2">截止昨日</text>{{ currentDate }}<text class="ml-2">排名</text><IconFont name="ask" size="16" class="ml-2" @click="handleRankAskClick"></IconFont></view>
<view v-if="activeTab === 'support'" class="absolute font-bold text-white bg-orange-500 top-0 rounded-full px-4 py-1" style="right: 0rpx; top: 50rpx; font-size: 23rpx; z-index: 999;" @tap="joinOrganization">助力码</view>
<view v-if="activeTab === 'support'" class="absolute font-bold text-white bg-orange-500 top-0 rounded-full px-4 py-1" style="right: -30rpx; top: -5rpx; font-size: 23rpx; z-index: 999;" @tap="joinOrganization">助力码</view>
</view>
<!-- <view v-if="activeTab === 'shanghai'" class="relative mb-2 text-white">
......@@ -124,9 +124,21 @@
</view>
</view>
<!-- 弹幕显示助力榜内容 -->
<view v-if="activeTab === 'support'" class="danmu-section">
<NativeDanmuComponent
:container-height="700"
:show-controls="true"
:track-count="3"
@danmu-click="handleDanmuClick"
@danmu-hover="handleDanmuHover"
ref="danmuRef"
/>
</view>
<!-- 我的排名卡片 -->
<!-- 特殊写法 因为直接写一个排名卡片排名数字有被截断问题 -->
<view v-if="myRank && topRanks.length > 0 && activeTab !== 'support'" class="my-rank-section">
<view v-if="myRank && topRanks.length > 0 && activeTab !== 'support'" class="my-rank-section" style="margin: 40rpx;">
<view class="my-rank-content">
<view class="my-rank-left">
<view class="my-rank-number">
......@@ -145,7 +157,7 @@
</view>
</view>
</view>
<view v-if="myRank && !topRanks.length && activeTab !== 'support'" class="my-rank-section">
<view v-if="myRank && !topRanks.length && activeTab !== 'support'" class="my-rank-section" style="margin: 40rpx;">
<view class="my-rank-content">
<view class="my-rank-left">
<view class="my-rank-number">
......@@ -192,7 +204,8 @@
import { ref, computed, onMounted, watch, nextTick } from 'vue'
import Taro from '@tarojs/taro'
import { IconFont } from '@nutui/icons-vue-taro';
import NumberRoll from './NumberRoll.vue'
// import NumberRoll from './NumberRoll.vue'
import NativeDanmuComponent from '@/components/NativeDanmuComponent.vue'
// 默认头像
const defaultAvatar = 'https://cdn.ipadbiz.cn/lls_prog/images/%E5%85%A8%E5%AE%B6%E7%A6%8F3_%E5%89%AF%E6%9C%AC.jpg?imageMogr2/strip/quality/60'
// 助力榜图片
......@@ -510,6 +523,27 @@ const refreshData = async () => {
await loadLeaderboardData(true)
}
/**
* 弹幕组件相关
*/
const danmuRef = ref(null)
// 处理弹幕点击事件
const handleDanmuClick = (familyData) => {
console.log('弹幕点击:', familyData)
Taro.showToast({
title: `点击了${familyData.familyName}`,
icon: 'none',
duration: 2000
})
}
// 处理弹幕悬停事件
const handleDanmuHover = (familyData) => {
console.log('弹幕悬停:', familyData)
}
/**
* 页面初始化
*/
......@@ -539,7 +573,7 @@ defineExpose({
// background: linear-gradient(180deg, var(--primary-color) 0%, var(--primary-color) 100%);
// background: var(--primary-color);
border-radius: 20rpx;
padding: 40rpx;
// padding: 40rpx;
margin: 30rpx;
margin-bottom: 0;
position: relative;
......
<!--
* @Date: 2025-09-01 13:07:52
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-10-28 13:32:48
* @LastEditTime: 2025-10-28 16:04:30
* @FilePath: /lls_program/src/pages/FamilyRank/index.vue
* @Description: 文件描述
-->
......@@ -42,7 +42,7 @@
<view v-if="!loading" class="rank-date relative">
<!-- <view class="flex items-center justify-center"><text class="mr-2">截止昨日</text>{{ currentDate }}<text v-if="activeTab !== 'shanghai'" class="ml-2">排名</text><IconFont name="ask" size="14" class="ml-2" @click="handleRankAskClick"></IconFont></view> -->
<view class="flex items-center justify-center"><text class="mr-2">截止昨日</text>{{ currentDate }}<text class="ml-2">排名</text><IconFont name="ask" size="14" class="ml-2" @click="handleRankAskClick"></IconFont></view>
<view v-if="activeTab === 'support'" class="absolute font-bold text-white bg-orange-500 top-0 rounded-full px-4 py-1" style="right: 40rpx; top: 50rpx; font-size: 23rpx;" @tap="joinOrganization">助力码</view>
<view v-if="activeTab === 'support'" class="absolute font-bold text-white bg-orange-500 top-0 rounded-full px-4 py-1" style="right: 45rpx; top: -5rpx; font-size: 23rpx;" @tap="joinOrganization">助力码</view>
</view>
<!-- 参与家庭数量显示 -->
......@@ -154,7 +154,18 @@
<view class="no-data-text">暂无助力排行榜更多数据</view>
</view> -->
</view>
<!-- 弹幕显示助力榜内容 -->
<view v-if="activeTab === 'support'" class="danmu-section mt-8">
<NativeDanmuComponent
:container-height="1200"
:show-controls="true"
:track-count="7"
@danmu-click="handleDanmuClick"
@danmu-hover="handleDanmuHover"
ref="danmuRef"
/>
</view>
<!-- 我的排名悬浮卡片 -->
......@@ -209,8 +220,8 @@ import { ref, computed, onMounted } from 'vue'
import Taro from '@tarojs/taro'
import { IconFont } from '@nutui/icons-vue-taro';
import BackToTop from '@/components/BackToTop.vue'
import NativeDanmuComponent from '@/components/NativeDanmuComponent.vue'
// import NumberRoll from '@/components/NumberRoll.vue'
import vueDanmaku from 'vue-danmaku'
// 默认头像
const defaultAvatar = 'https://cdn.ipadbiz.cn/lls_prog/images/%E5%85%A8%E5%AE%B6%E7%A6%8F3_%E5%89%AF%E6%9C%AC.jpg?imageMogr2/strip/quality/60'
const supportImg = 'https://cdn.ipadbiz.cn/lls_prog/images/support_img_1.png'
......@@ -268,6 +279,26 @@ const handleRankAskClick = () => {
}
/**
* 弹幕组件相关
*/
const danmuRef = ref(null)
// 处理弹幕点击事件
const handleDanmuClick = (familyData) => {
console.log('弹幕点击:', familyData)
Taro.showToast({
title: `点击了${familyData.familyName}`,
icon: 'none',
duration: 2000
})
}
// 处理弹幕悬停事件
const handleDanmuHover = (familyData) => {
console.log('弹幕悬停:', familyData)
}
/**
* 触发数字滚动动画
*/
const triggerNumberRoll = () => {
......@@ -1039,7 +1070,5 @@ onMounted(async () => {
}
}
}
}
</style>
......