在nuxt3以及vue3中实现弹幕留言板效果

14,046次阅读
没有评论

共计 5709 个字符,预计需要花费 15 分钟才能阅读完成。

在我们开发自己的博客时候都会有留言功能,除了传统的类似评论的留言板,还有弹幕形式就像这样的效果,今天就记录一下实现的方法,大家可以去原网站看看小贺的神奇网站 (mxll.xyz),这个也是我的博客,目前也正在完善

在 nuxt3 以及 vue3 中实现弹幕留言板效果

大致的思路就是弹幕盒子从右到左移动,溢出屏幕时候销毁盒子就可以了,先上完整代码然后再进行分析。

第一阶段:准备变量

const danmusList = ref([]);
const danmus = ref([]);
const currentDanmuIndex = ref(0);
const danmuContainer = ref(null);
const usInp = ref("");
const num = ref(0);
const player = ref(null);

这里是创建的变量,使用了 ts,如果是 js 去除类型定义就行了并不影响。

danmusList 是获取的后台的弹幕列表。

danmus 是弹幕列表用于渲染,可能有人会问为啥不用 danmusList 渲染,别忘了弹幕消失后还要删除 dom,但是在 vue 这些框架中只需要更改数据就行了。别忘了那句话数据驱动视图!!

currentDanmuIndex 是弹幕行数的索引,就是在页面上看到的第几行,这个是用于计算的。

currentDanmuIndex 是获取存放弹幕的盒子。

usInp 是输入弹幕。

num 用作结束定时器的判断条件。

player 保存定时器函数。

第二阶段:编写函数

创建一个用于控制弹幕列表的函数,直接往 danmus 中添加要循环的弹幕的信息,然后定义一个定时器在这个弹幕离开屏幕后删除这个数据就好了,这里说两点 setTimeout 在执行完毕就会销毁,然后可能还有人会问我怎么知道 16 秒后我的弹幕就会离开屏幕,这里先卖个关子,在下面会提到。

const addDanmu = (item: any) => {danmus.value.push(item);
  // 等待动画完成后移除弹幕
  setTimeout(() => {const index = danmus.value.findIndex((d: any) => d.id === item.id);
    if (index !== -1) {danmus.value.splice(index, 1);
    }
  }, 16000);
};

这个函数是用于控制弹幕的轨道,说人话就说屏幕显示几行弹幕,其中 minTop 表示第一个弹幕距离顶部的距离,然后 lineCount 就表示弹幕的行数,剩下的就是计算每一行弹幕应该距离顶部的距离啦。

const calculateTop = () => {
  const minTop = 100;
  const lineCount = 15;
  const availableHeight = danmuContainer.value.offsetHeight - minTop || 0;
  const lineHeight = availableHeight / lineCount;
  const lineIndex = currentDanmuIndex.value++ % lineCount;
  return lineIndex * lineHeight + minTop;
};

重点来了 (敲黑板),这个函数是请求数据然后添加数据,这里要注意吧请求数据换成自己的,然后判断在没有数据时候结束函数 (这里其实有 bug,最后再说),创建一个定时器添加重置条件,定时器的无限循环的,然后使用 addDanmu 函数添加弹幕的信息,注意看 addDanmu 函数中传的 duration 这个值,这个是用于弹幕从左到右的时间,之前我说清除弹幕是一个定时器,那个定时器的时间就和这个有关,css 动画效果 animationDuration 表示的是动画运动一个周期的时间,就是一来一回,咱们只需要去不需要回来,所以清除变量的定时器是这个时间的一半就好。最后这个 player 这个定时器的执行时间越快弹幕距离就越近。

const danmuFn = async () => {
  num.value = 0;
  const res = await danmuApi(); // 注意这里
  danmusList.value = res.data;  // 还有这里

  if (danmusList.value.length === 0) return;
  player.value = setInterval(() => {if (num.value>= danmusList.value.length) {num.value = 0;}
    addDanmu({id: uuid(),
      text: danmusList.value[num.value]["danmu"],
      top: calculateTop(),
      left: "100vw",
      duration: Math.random() * (30 - 27) + 27,
      color: danmusList.value[num.value]["act"] ? "#f50" : "#fff",
    });
    num.value = num.value + 1;
  }, 100);
};

这个是点击按钮添加弹幕,这个判断是空就结束,主要是当用户添加弹幕没必要在从新渲染弹幕盒子,直接添加一个数据就好了。

const addDanmuFn = async () => {if (usInp.value.replace(/s*/g, "") ==='') return
  const res = await danmuAddApi({danmu: usInp.value.replace(/s*/g, ""),
  });
  if (res.code) {
    addDanmu({id: uuid(),
      text: usInp.value.replace(/s*/g, ""),
      top: calculateTop(),
      left: "100vw",
      duration: Math.random() * (30 - 28) + 28,
      color: "#f50",
    });
  }
  usInp.value = "";
};

最后还有两点,在 nuxt 中使在 onNuxtReady 中执行函数,vue 中使用 onMounted 就可以,最后记得组件销毁时候结束结束定时器。

onNuxtReady(() => {danmuFn();
});
onUnmounted(() => {clearInterval(player.value);
});

第三阶段:编写样式

js 完成之后就要开始 html 部分以及 css 部分,都比较简单。

    
{{danmu.text}}
.danmu-container { position: absolute; z-index: -1; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; .danmu { position: absolute; white-space: nowrap; color: white; padding: 5px; user-select: none; opacity: 0.8; animation-name: slide; animation-timing-function: linear; } @keyframes slide { from {transform: translateX(0); } to {transform: translateX(-(100vw + 100%)); } } }

以下是完成的代码,根据自己的需求进行更改即可:需要注意的是里面有一些引入的公共方法还有图片以及 css 变量等需要根据自己的代码进行更改!






结语

之前提到了这个有 bug,是在于如果最开始弹幕只有一条,那么整个屏幕的弹幕都会是这一条,后续我进行了优化,打算实现的效果是在弹幕较少的时候,用于存放弹幕数据的数组清空时候再次执行添加弹幕的函数但是效果不佳,最后就在数据库添加了十几条初始的弹幕这样会好看一些。

还有一点就是有的网站弹幕是可以清空并且暂停和从新开始滚动,这个我们已经有开始弹幕的函数了,只用添加有一个点击事件然后清空存放数据的数组即可~

最后欢迎大家评论区留言

原文地址: 在 nuxt3 以及 vue3 中实现弹幕留言板效果

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-10-07发表,共计5709字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)