Vue自拟弹幕组件bug寻求解答或提示?

在尝试写一段弹幕组件,代码如下:

import { onMounted, ref, nextTick } from 'vue'

import io from 'socket.io-client'

export default {

setup () {

let socket

const barrages = ref([]) // 存放弹幕数据

const winWidth = ref(window.innerWidth) // 获得屏幕宽度

const barrageEls = ref([]) // 获取每条弹幕

onMounted(() => {

socket = io('http://localhost:3002')

socket.on('connect', () => {

console.log(socket.id, '监听客户端连接成功-connect')

})

socket.on('to-client', async (data) => {

// 计算最新一条弹幕的文字宽度,以便记录划出距离

const canvas = document.createElement('canvas')

const context = canvas.getContext('2d')

context.font = '12pt Avenir'

const {

width

} = context.measureText(data.name + data.discourse)

// 追加弹幕到 barrages 中

barrages.value[barrages.value.length] = {

msg: data.name + ':' + data.discourse,

speed: Math.round(Math.random() * 3), // 随机速度

top: Math.round(Math.random() * 100)

}

await nextTick()

// 弹幕画出动画

const timer = setInterval(function () {

// 获得新添加的弹幕 [barrageEls.value.length - 1] 并对其位置进行移动

if (barrageEls.value[barrageEls.value.length - 1].offsetLeft < -(Math.ceil(width))) {

// 停止动画本质是停止定时器

clearInterval(timer)

}

barrageEls.value[barrageEls.value.length - 1].style.left = winWidth.value--

}, Math.round(Math.random() * 3))

})

})

return {

barrages,

barrageEls,

winWidth

}

}

}

但实际运行起来发现有如下 bug :

  • 如果相近时间内提交两条弹幕,会导致速度叠加;
  • 每条弹幕的左坐标位置并没有随弹幕内容变化;
  • 在第一条弹幕移动时间内可以进行重复提交,但 clearInterval(timer) 后无法触发新弹幕滚动

目前还没有想到解决办法,还望可以得到提示,谢谢!


依照一楼的方案修改代码,解决了问题,但是又暴露了新的问题:
新的一条弹幕总会在视图上清楚上一条弹幕动画,我在想是否是因为 [barrageEls.value.length - 1] 的问题导致的,我尝试如下修改:

// 在新弹幕来的时候遍历对象判断该结束哪个动画

barrages.value.forEach(item => {

if (item.left < -item.width) {

clearInterval(item.timer)

}

})

……

barrages.value.push({

width: width, // 保存该弹幕宽度

msg: data.name + ':' + data.discourse,

speed: Math.round(Math.random() * 3),

top: Math.round(Math.random() * 100),

left: winWidth.value,

timer: null // 保存该弹幕动画

})

……

const timer = setInterval(function () {

// 将终止动画函数放到了外面

barrages.value[barrages.value.length - 1].left--

barrageEls.value[barrageEls.value.length - 1].style.left = barrages.value[barrages.value.length - 1].left + 'px'

}, Math.round(Math.random() * (10 - 5) + 5))

barrages.value[barrages.value.length - 1].timer = timer // 存储定时器

但是依旧会清除前面的弹幕 ???


又修改了一版,解决了新弹幕清楚旧弹幕的问题,但是此写法无法终止定时器,代码如下:

<template v-for="(item, index) in barrages" :key="index">

<div :style="{ top: item.top + '%', left: item.maxW + 'px' }">

{{ item.timer(item) }} // 运行当前对象中的定时器函数

{{ item.msg }}

</div>

</template>

// 追加弹幕到 barrages 中

let newBarrage = {

msg: data.name + ':' + data.discourse,

top: Math.round(Math.random() * 100),

speed: Math.round(Math.random() * (10 - 5) + 5),

maxW: maxW, // maxW 屏幕总宽度

minW: width, // width 当前弹幕占用宽度

timer: (item) => {

timer(item)

}

}

function timer (item) {

let timer = setInterval(() => {

if (item.maxW < -item.minW) {

clearInterval(timer) // 该方案此处无法终止定时器

}

item.maxW--

}, item.speed)

}

barrages.value.push(newBarrage)

仍在想办法 Ing ……


最终使用组件解决,传送门链接:https://www.skypack.dev/view/vue3-danmaku


回答:

import { onMounted, ref, nextTick } from 'vue'

import io from 'socket.io-client'

export default {

setup () {

let socket

const barrages = ref([]) // 存放弹幕数据

const winWidth = ref(window.innerWidth) // 获得屏幕宽度

onMounted(() => {

socket = io('http://localhost:3002')

socket.on('connect', () => {

console.log(socket.id, '监听客户端连接成功-connect')

})

socket.on('to-client', async (data) => {

// 计算最新一条弹幕的文字宽度,以便记录划出距离

const canvas = document.createElement('canvas')

const context = canvas.getContext('2d')

context.font = '12pt Avenir'

const {

width

} = context.measureText(data.name + data.discourse)

// 追加弹幕到 barrages 中

const newBarrage = {

msg: data.name + ':' + data.discourse,

speed: Math.round(Math.random() * 3), // 随机速度

top: Math.round(Math.random() * 100),

left: winWidth.value,

width: width,

timer: null

}

barrages.value.push(newBarrage)

await nextTick()

// 弹幕画出动画

newBarrage.timer = setInterval(function () {

// 获得新添加的弹幕 [barrageEls.value.length - 1] 并对其位置进行移动

if (newBarrage.left < -newBarrage.width) {

// 停止动画本质是停止定时器

clearInterval(newBarrage.timer)

}

newBarrage.left--

}, newBarrage.speed)

})

})

return {

barrages,

winWidth

}

}

}


回答:

最终使用组件解决,传送门链接:https://www.skypack.dev/view/vue3-danmaku

以上是 Vue自拟弹幕组件bug寻求解答或提示? 的全部内容, 来源链接: utcz.com/p/934607.html

回到顶部