实现一个简单的弹幕效果

前言

之前一直想实现一下弹幕效果,因为种种原因(ps:哈哈,就是太懒了)一直没有做。正好最近比较闲,因此打算来实现一下,先简单描述下具体效果,页面展示一段视频,视频下方有一个文本输入框,可以输入弹幕,输入完成之后,弹幕轮播显示在视频上方。

页面结构

分为视频和弹幕输入两部分,视频部分包含了视频标签和展示弹幕的文字层,都使用绝对定位,并让弹幕显示在视频上面(z-index控制层级,数值越大,位置就在最上面)。弹幕输入部位包含一个文本输入框和按钮

ini 复制代码
<div class="container">
    <div id="barrage-container"></div>
    <video src="/video.mp4" controls ></video>
</div>
<div class="send-box">
    <input id="send-input" type="text" placeholder="请输入弹幕内容">
    <button id="send-btn">发送</button>
</div>

初步尝试

弹幕的简单运行逻辑:输入弹幕之后,点击发送,弹幕就从视频上面的最左边移动到最右边并消失

因此好像可以实现css3的动画属性实现弹幕移动效果,先简单尝试一下。给发送按钮添加点击事件,如果输入框不存在内容,直接return出去。有值再创建一个div元素,并把输入框的文本内容赋值给div元素,添加元素类名,在css中设置动画。再设置一个范围内的随机值作为div元素的top值(创建元素的代码在下面展示)。最后把div元素添加到弹幕模块中,并清空输入框的值。

注:每个弹幕元素的动画执行完成后,可以移除该弹幕元素,及时释放不再需要的 DOM 节点,这样可以减少页面的内存占用,提高页面的整体性能

ini 复制代码
const barrageContainer = document.getElementById('barrage-container')
const input = document.getElementById('send-input');
const button = document.getElementById('send-btn');
button.addEventListener('click', function () {
    let value = input.value.trim()
    if(!value){
        return
    }
    let dom = createElement(value, true)
    barrageContainer.appendChild(dom)
    input.value = ''
});

实现弹幕移动动画,弹幕元素使用绝对定位,并改变left值和transform在水平方向上的移动距离。

这样可以简单实现输入弹幕,并展示的效果。但是没有考虑到原本有弹幕数据展示的情况。

功能改善

首先模拟写了一些假数据(ps:正常情况是请求后台的弹幕数据展示,估计应该就复杂了,这里就纯前端展示了)。创建一个初始化弹幕的函数,用来循环这些数据,创建弹幕元素。因为要创建多个元素,所以使用了创建文档片段的方法document.createDocumentFragment(),等元素都添加完成之后,一次性添加到弹幕模块中。

js 复制代码
function initBarrage() {
  // 创建一个文档片段(不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染)
  let frag = document.createDocumentFragment();
  data.forEach((item) => {
    let domItem = createElement(item.text, false)
     // 将所有节点添加到这个文档片段中
    frag.appendChild(domItem);
  })
  // 将这个文档片段一次性添加到元素中
  barrageContainer.appendChild(frag);
}

封装创建弹幕元素的方法,以便于在一开始加载弹幕数据和输入弹幕的时候使用。在该方法中,初始加载弹幕需要设置动画的延迟时间,不然弹幕会重叠在一起,同时监听弹幕元素动画,在动画开始时才显示。

之前随机获取的弹幕位置的top值,如果在有弹幕显示的情况下,再发送弹幕,随机top值可能会重复,造成弹幕元素重叠。因此定义一个数组来跟踪当前正在显示的弹幕的top值,然后在生成新的top时,检查数组中是否包含该top值。如果存在,需要重新生成一个新的top值。最后,在弹幕动画结束时,我们从该数组中移除对应的top值,以便后续的弹幕可以使用这个值。

js 复制代码
let interval = 1  //动画延迟时间
let currentHeights = []; //获取显示的弹幕top值
function createElement(value, isSend) {
  let barrage = document.createElement('div')
  barrage.textContent = value
  barrage.className = 'barrage'
  barrage.style.top = getRandomTop(5, barrageHeight * 0.6) + 'px'

  if (!isSend) {
    barrage.style.animationDelay = interval + 's'
    barrage.style.opacity = 0
    barrage.addEventListener('animationstart', function () {
      barrage.style.opacity = 1
    })
    interval += 2
  }

  barrage.addEventListener('animationend', function () {
    barrageContainer.removeChild(barrage);
    currentHeights = currentHeights.filter(item => item !== parseInt(barrage.style.top));
  })
  return barrage
}


//随机获取高度
function getRandomTop(start, end) {
  let top;
  do {
    let randomNumber = start + Math.random() * (end - start)
    top = parseFloat(randomNumber.toFixed(2));
  } while (currentHeights.includes(top))
  currentHeights.push(top);
  return top;
}

按照以上代码就简单实现了弹幕效果。当然还有很多问题,比如弹幕速度的控制、弹幕分布密度、弹幕风格、页面性能等,看来还有的研究啊。

相关推荐
m0_5485147713 分钟前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
AndrewPerfect13 分钟前
xss csrf怎么预防?
前端·xss·csrf
Calm55016 分钟前
Vue3:uv-upload图片上传
前端·vue.js
浮游本尊21 分钟前
Nginx配置:如何在一个域名下运行两个网站
前端·javascript
m0_7482398321 分钟前
前端bug调试
前端·bug
m0_7482329224 分钟前
[项目][boost搜索引擎#4] cpp-httplib使用 log.hpp 前端 测试及总结
前端·搜索引擎
新中地GIS开发老师29 分钟前
《Vue进阶教程》(12)ref的实现详细教程
前端·javascript·vue.js·arcgis·前端框架·地理信息科学·地信
m0_7482495431 分钟前
前端:base64的作用
前端
html组态37 分钟前
web组态可视化编辑器
前端·物联网·编辑器·web组态·组态·组态软件
~央千澈~44 分钟前
如果你的网站是h5网站,如何将h5网站变成小程序-除开完整重做方法如何快速h5转小程序-h5网站转小程序的办法-优雅草央千澈
前端·apache