当前位置: 首页 > 知识库问答 >
问题:

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

刘昌翰
2023-07-15

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

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

共有2个答案

应志用
2023-07-15

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

丌官高远
2023-07-15
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    }  }}
 类似资料:
  • Mudu.Room.Barrage 弹幕组件 Barrage.New事件 Barrage.New事件会在收到新的弹幕时被触发 Mudu.MsgBus.On( // 事件名,值为"Barrage.New" "Barrage.New", // 事件处理函数,参数为弹幕对象 function (barrage) { barrage = JSON.parse(barrage)

  • 本文向大家介绍详解用vue编写弹出框组件,包括了详解用vue编写弹出框组件的使用技巧和注意事项,需要的朋友参考一下 前言 最近研究了用vue编写弹出框的组件,发现其实这里面的门道还是有很多的。这篇文完全是用来记录总结下最近的学习成果,同时也希望能够帮得上正在学习纠结的你~ps:本文假设你已经了解vue2.0相关框架,因此适合有一定vue2.0基础的同学阅读。 设计组件的思考 其实单纯的编写一个弹出

  • 在view/HomeView.vue使用自定义组件时一直找不到,只能在App.vue里能找到, 报错:No loader is configured for ".vue" files: packages/components/card/Card.vue

  • 本文向大家介绍Vue.js路由组件vue-router使用方法详解,包括了Vue.js路由组件vue-router使用方法详解的使用技巧和注意事项,需要的朋友参考一下 使用Vue.js + vue-router 创建单页应用是非常简单的。只需要配置组件和路由映射,然后告诉 vue-router 在哪里渲染即可。 一、普通方式基本例子: 二、块化机制编程基本例子,以在vue-cli中的使用方法为例

  • 对于vue响应式原理,里面的watcher。有个疑问。 (1)每个组件只有一个watcher,当数据被读取会被添加到相应的dep中。 (2)在某处用到该数据就会new一个新的watcher,然后添加到dep中呢。 这两种说法哪个对? 给出两个例子,帮忙分析,感谢。 例如,这个图片中dep1和dep2。如果按说法(1),那图中的三个watcher应该是同一个。但是vue官方文档的说法是图2到底哪个才

  • 本文向大家介绍很棒的vue弹窗组件,包括了很棒的vue弹窗组件的使用技巧和注意事项,需要的朋友参考一下 弹窗是一个项目必备的复用利器,所以封装起来,保证项目ui一致,是很有必要的。学了一段时间vue,想想还是用vue写一下吧。用的很小白,但是会写出来了,说明我也有进步一丢丢了。继续加油…. 代码贴图如下,样式比较丑,不要介意… 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐