hookehuyr

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

改进弹幕宽度测量功能,增加重试机制和更保守的默认值计算
优化动画启动时机,确保宽度测量完成后再开始
...@@ -105,9 +105,16 @@ const WINDOW_WIDTH = SYSTEM_INFO.windowWidth ...@@ -105,9 +105,16 @@ const WINDOW_WIDTH = SYSTEM_INFO.windowWidth
105 105
106 // px 转 rpx 106 // px 转 rpx
107 const toRpx = (px) => (px * CONTAINER_WIDTH) / WINDOW_WIDTH 107 const toRpx = (px) => (px * CONTAINER_WIDTH) / WINDOW_WIDTH
108 -// 获取弹幕宽度(rpx) 108 +// 获取弹幕宽度 - 增强版,提供更安全的默认值
109 const getDanmuWidth = (danmu) => { 109 const getDanmuWidth = (danmu) => {
110 - return danmu?.widthRpx && danmu.widthRpx > 0 ? danmu.widthRpx : DANMU_WIDTH 110 + if (danmu.widthRpx && danmu.widthRpx > 0) {
111 + return danmu.widthRpx
112 + }
113 + // 如果没有测量到宽度,使用更保守的默认值
114 + // 根据内容长度动态估算,避免过短导致重叠
115 + const contentLength = danmu.data?.familyName?.length || 0
116 + const estimatedWidth = Math.max(DANMU_WIDTH, contentLength * 30 + 100) // 每字符约30rpx + 100rpx边距
117 + return Math.min(estimatedWidth, DANMU_WIDTH * 2) // 最大不超过2倍默认宽度
111 } 118 }
112 // 重新计算时长,保证速度一致 119 // 重新计算时长,保证速度一致
113 const recalculateDuration = (danmu) => { 120 const recalculateDuration = (danmu) => {
...@@ -115,19 +122,38 @@ const recalculateDuration = (danmu) => { ...@@ -115,19 +122,38 @@ const recalculateDuration = (danmu) => {
115 const totalDistance = CONTAINER_WIDTH + width + EXTRA_DISTANCE 122 const totalDistance = CONTAINER_WIDTH + width + EXTRA_DISTANCE
116 danmu.duration = (totalDistance / (props.danmuSpeed * 0.6)) * 1000 123 danmu.duration = (totalDistance / (props.danmuSpeed * 0.6)) * 1000
117 } 124 }
118 -// 测量弹幕真实宽度(px),存为 rpx 125 +// 测量弹幕真实宽度(px),存为 rpx - 增强版,支持重试和更保守的默认值
119 -const measureDanmuWidth = (danmu) => new Promise((resolve) => { 126 +const measureDanmuWidth = (danmu, retryCount = 0) => new Promise((resolve) => {
127 + const maxRetries = 3
128 + const retryDelay = 50 // 50ms 重试间隔
129 +
120 try { 130 try {
121 const selector = `#danmu-${danmu.id} .danmu-content` 131 const selector = `#danmu-${danmu.id} .danmu-content`
122 Taro.createSelectorQuery().select(selector).boundingClientRect(rect => { 132 Taro.createSelectorQuery().select(selector).boundingClientRect(rect => {
123 - if (rect && rect.width) { 133 + if (rect && rect.width && rect.width > 0) {
124 danmu.widthRpx = toRpx(rect.width) 134 danmu.widthRpx = toRpx(rect.width)
125 - }
126 resolve(getDanmuWidth(danmu)) 135 resolve(getDanmuWidth(danmu))
136 + } else if (retryCount < maxRetries) {
137 + // 测量失败,延迟重试
138 + setTimeout(() => {
139 + measureDanmuWidth(danmu, retryCount + 1).then(resolve)
140 + }, retryDelay)
141 + } else {
142 + // 重试失败,使用更保守的默认宽度(比实际内容更大)
143 + danmu.widthRpx = DANMU_WIDTH * 1.5 // 使用1.5倍默认宽度作为安全值
144 + resolve(getDanmuWidth(danmu))
145 + }
127 }).exec() 146 }).exec()
128 } catch (e) { 147 } catch (e) {
148 + if (retryCount < maxRetries) {
149 + setTimeout(() => {
150 + measureDanmuWidth(danmu, retryCount + 1).then(resolve)
151 + }, retryDelay)
152 + } else {
153 + danmu.widthRpx = DANMU_WIDTH * 1.5
129 resolve(getDanmuWidth(danmu)) 154 resolve(getDanmuWidth(danmu))
130 } 155 }
156 + }
131 }) 157 })
132 158
133 // 轨道系统 159 // 轨道系统
...@@ -168,7 +194,7 @@ const getDanmuStyle = (danmu, trackIndex) => { ...@@ -168,7 +194,7 @@ const getDanmuStyle = (danmu, trackIndex) => {
168 194
169 return { 195 return {
170 transform: `translateX(${danmu.x}rpx)`, 196 transform: `translateX(${danmu.x}rpx)`,
171 - transition: danmu.isMoving ? `transform ${(danmu.remainingDuration ?? danmu.duration)}ms linear` : 'none', 197 + transition: danmu.isMoving ? 'transform ' + (danmu.remainingDuration ?? danmu.duration) + 'ms linear' : 'none',
172 opacity: danmu.opacity || 1, 198 opacity: danmu.opacity || 1,
173 // 明确设置垂直位置 199 // 明确设置垂直位置
174 position: 'absolute', 200 position: 'absolute',
...@@ -279,12 +305,17 @@ const addDanmuToTrack = (danmu, targetTrack = null, options = {}) => { ...@@ -279,12 +305,17 @@ const addDanmuToTrack = (danmu, targetTrack = null, options = {}) => {
279 track.danmus.push(danmu) 305 track.danmus.push(danmu)
280 track.lastDanmuTime = Date.now() 306 track.lastDanmuTime = Date.now()
281 307
282 - // 启动弹幕动画 308 + // 启动弹幕动画 - 确保宽度测量完成后再开始
283 nextTick(async () => { 309 nextTick(async () => {
310 + // 等待宽度测量完成,确保获得准确宽度
284 await measureDanmuWidth(danmu) 311 await measureDanmuWidth(danmu)
285 recalculateDuration(danmu) 312 recalculateDuration(danmu)
313 +
286 // 重置起始时间,保证时长重新计算后动画正确 314 // 重置起始时间,保证时长重新计算后动画正确
287 danmu.startTime = Date.now() 315 danmu.startTime = Date.now()
316 +
317 + // 再次等待一个 tick,确保 DOM 完全更新
318 + await nextTick()
288 startDanmuAnimation(danmu, track) 319 startDanmuAnimation(danmu, track)
289 }) 320 })
290 321
......