[兔了个兔]——兔年祝福弹幕

858 阅读3分钟

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

弹幕功能想必大家都不陌生,今天做一个单人弹幕小游戏,在输入框中输入祝福话语点击发送就能在上面容器中从右到左飘过。

image.png

实现

要想实现弹幕功能,我们必须确保以下几个方面:

  1. 发送的弹幕不能重叠。
  2. 弹幕之间错行出现。
  3. 弹幕从右到左的移动。 将以上三个问题解决了我们的弹幕功能也就出来了,剩下的加下细节就可以啦。那么我们开始一个个来实现上述功能,技术栈我用的vue2+elementui,在html页面中引入对应的cdn链接进行开发。

布局

首先画出静态页面,利用flex或者position将容器放到页面中间,如果有需要可以在容器上添加上自己喜欢的背景图:

    <!-- 引入vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
    <!-- 引入样式 -->
    <link
      rel="stylesheet"
      href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
    />
    <!-- 引入组件库 -->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <div id="app">
      <div class="barrage-wrapper" ref="barrageWrapper">
        <div class="barrage-main">
          <div class="barrage-main-dm" ref="barrageMainDm"></div>
        </div>
        <el-input v-model="text" clearable placeholder="请输入祝福语"      @keyup.enter.native="handleAddContent">
          <template slot="append">
            <i class="el-icon-position" @click="handleAddContent" ></i>
          </template>
        </el-input>
      </div>
    </div>

弹幕数组

为了弹幕之间不重叠,我们利用setInterval让发送的话语间隔出现在屏幕上,这样就有一个问题,如果我们发送的弹幕间隔比较短,上一个弹幕还没出现,现在也发送了,就必须要记住发送过的弹幕,所以我们需要声明一个数组用来保存数据,之所以用数组也是为了后续方便提取数据。

    /** 弹幕数组 初始化数据*/
    barrages: [ {
        content: '恭喜发财'
      },
      {
        content: '兔年大吉'
      },
      {
        content: '新年快乐'
      }]

dom池

弹幕可以多行展示,不能只堆积到一行当中,每一行我们也需要设置一个上限,尽量确保每个弹幕都能清楚展示。这里我们在弹幕出现前就创建好小容器,而不是弹幕出现后再创建容器。我们将每一条弹幕当成一个小容器,通过行数与上限数在大容器里面设置好一个个小容器,就像网格一样,创建出来的就是dom池,我们初始化的时候就是再创建dom池。

2222.png 有了dom池,里面的每个dom我们可以重复利用,提高性能,并且弹幕的移动,可以通过transform:translate加上animation移动每个dom进行实现。

        init: function () {
               //初始化清空dom池、定时器等
                this.domPool = [];
                this.barrageMainDm.innerHTML = ``;
                clearInterval(this.intervalDM);
                // 创建div小容器 双循环一个行 一个列
                for (let j = 0; j < 5; j++) {
                let doms = [];
                for (let i = 0; i < 5; i++) {
                let dom = document.createElement('div');
                // 设置样式
                dom.className = 'barrage-item';
                // 根据容器宽度确定每个dom的位置
                dom.style.transform = `translate(${this.barMainWidth}px,0)`;
                // 设置top确定在那一列
                dom.style.top =
                j * (this.barrageMainDm.clientHeight / 5) +
                'px';
                // 动画结束重复利用
                dom.addEventListener('animationend', () => {
                dom.className = 'barrage-item';
                dom.style.transform = `translate(${this.barMainWidth}px,0)`;
                dom.style.animation = null;
                // 清空自定义样式
                this.dmStyles.forEach((key) => {
                dom.style[key] = null;
                });
                if (this.domPool[i][j]) {
                this.domPool[i][j].isFree = false;
                }
                });
                doms.push({
                    row: j,
                    col: i,
                    el: dom,
                    //是否正在用
                    isUse: false,
                    //是否空闲
                    isFree: false
                });
                }
                this.domPool.push(doms);
        }

这个就是核心代码,弹幕的移动,添加到空闲的dom当中都是围绕着dom池进行操作的。

播放弹幕

利用上面的dom池我们就可以播放弹幕,首先我们从上面弹幕数组中获取弹幕,利用数组的shift方法获取数组的首个元素,同时我们用watch监听数组长度变化,当数组长度为0就清除定时器:

   watch:{
     'barrages.length': function (len) {
        if (len === 0) {
          setTimeout(() => {
            this.pauseDm();
          }, 8000);
        }
      }
   }

我们输入新语句的时候也通过push方法去添加弹幕,这也是选择数组保存弹幕的原因——方便添加、获取。 下一步我们找到空间的dom将内容添加到dom中,同时添加动画实现移动。

     @keyframes barrage-run {
        0% {
        }
        100% {
          transform: translate(-100%, 0);
        }
      }

这样我们弹幕的播放也就实现了。

总结

以上就是弹幕实现的全过程,重点是dom池的创建,后续都是围绕dom池在操作。写下祝福或者心愿让这些出现在弹幕上吧。