实现一个简单的弹幕效果

前言

之前一直想实现一下弹幕效果,因为种种原因(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;
}

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

相关推荐
qq_3901617723 分钟前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫1 小时前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web
贩卖纯净水.1 小时前
Chrome调试工具(查看CSS属性)
前端·chrome
栈老师不回家2 小时前
Vue 计算属性和监听器
前端·javascript·vue.js