hookehuyr

fix(弹幕组件): 增强弹幕宽度测量逻辑和默认值处理

改进弹幕宽度测量功能,增加重试机制和更保守的默认值计算
优化动画启动时机,确保宽度测量完成后再开始
......@@ -105,9 +105,16 @@ const WINDOW_WIDTH = SYSTEM_INFO.windowWidth
// px 转 rpx
const toRpx = (px) => (px * CONTAINER_WIDTH) / WINDOW_WIDTH
// 获取弹幕宽度(rpx)
// 获取弹幕宽度 - 增强版,提供更安全的默认值
const getDanmuWidth = (danmu) => {
return danmu?.widthRpx && danmu.widthRpx > 0 ? danmu.widthRpx : DANMU_WIDTH
if (danmu.widthRpx && danmu.widthRpx > 0) {
return danmu.widthRpx
}
// 如果没有测量到宽度,使用更保守的默认值
// 根据内容长度动态估算,避免过短导致重叠
const contentLength = danmu.data?.familyName?.length || 0
const estimatedWidth = Math.max(DANMU_WIDTH, contentLength * 30 + 100) // 每字符约30rpx + 100rpx边距
return Math.min(estimatedWidth, DANMU_WIDTH * 2) // 最大不超过2倍默认宽度
}
// 重新计算时长,保证速度一致
const recalculateDuration = (danmu) => {
......@@ -115,18 +122,37 @@ const recalculateDuration = (danmu) => {
const totalDistance = CONTAINER_WIDTH + width + EXTRA_DISTANCE
danmu.duration = (totalDistance / (props.danmuSpeed * 0.6)) * 1000
}
// 测量弹幕真实宽度(px),存为 rpx
const measureDanmuWidth = (danmu) => new Promise((resolve) => {
// 测量弹幕真实宽度(px),存为 rpx - 增强版,支持重试和更保守的默认值
const measureDanmuWidth = (danmu, retryCount = 0) => new Promise((resolve) => {
const maxRetries = 3
const retryDelay = 50 // 50ms 重试间隔
try {
const selector = `#danmu-${danmu.id} .danmu-content`
Taro.createSelectorQuery().select(selector).boundingClientRect(rect => {
if (rect && rect.width) {
if (rect && rect.width && rect.width > 0) {
danmu.widthRpx = toRpx(rect.width)
resolve(getDanmuWidth(danmu))
} else if (retryCount < maxRetries) {
// 测量失败,延迟重试
setTimeout(() => {
measureDanmuWidth(danmu, retryCount + 1).then(resolve)
}, retryDelay)
} else {
// 重试失败,使用更保守的默认宽度(比实际内容更大)
danmu.widthRpx = DANMU_WIDTH * 1.5 // 使用1.5倍默认宽度作为安全值
resolve(getDanmuWidth(danmu))
}
resolve(getDanmuWidth(danmu))
}).exec()
} catch (e) {
resolve(getDanmuWidth(danmu))
if (retryCount < maxRetries) {
setTimeout(() => {
measureDanmuWidth(danmu, retryCount + 1).then(resolve)
}, retryDelay)
} else {
danmu.widthRpx = DANMU_WIDTH * 1.5
resolve(getDanmuWidth(danmu))
}
}
})
......@@ -168,7 +194,7 @@ const getDanmuStyle = (danmu, trackIndex) => {
return {
transform: `translateX(${danmu.x}rpx)`,
transition: danmu.isMoving ? `transform ${(danmu.remainingDuration ?? danmu.duration)}ms linear` : 'none',
transition: danmu.isMoving ? 'transform ' + (danmu.remainingDuration ?? danmu.duration) + 'ms linear' : 'none',
opacity: danmu.opacity || 1,
// 明确设置垂直位置
position: 'absolute',
......@@ -279,12 +305,17 @@ const addDanmuToTrack = (danmu, targetTrack = null, options = {}) => {
track.danmus.push(danmu)
track.lastDanmuTime = Date.now()
// 启动弹幕动画
// 启动弹幕动画 - 确保宽度测量完成后再开始
nextTick(async () => {
// 等待宽度测量完成,确保获得准确宽度
await measureDanmuWidth(danmu)
recalculateDuration(danmu)
// 重置起始时间,保证时长重新计算后动画正确
danmu.startTime = Date.now()
// 再次等待一个 tick,确保 DOM 完全更新
await nextTick()
startDanmuAnimation(danmu, track)
})
......