vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue弹幕组件

基于Vue设计实现一个弹幕组件

作者:前端小张同学

这篇文章主要给大家分享一个开发中常见的需求,接下来将为大家详细介绍弹幕的实现以及设计思路一步一步描述出来,希望大家能够喜欢

1.关于弹幕设计思想

1.1业务层 | 视图层(全局组件)

从业务角度来说,如果你设计的是全局弹幕组件,你要考虑以下几点。

设计方案考虑完整了以后,你将可以开始考虑 数据层的设计

1.2数据层

从数据角度来说每一条弹幕无非是一个element,然后把弹幕内容放到这个element元素中,并且给 element 添加动画,那接下来,你应该这样考虑。

数据设计方案考虑完整了以后,你将可以开始考虑 数据管理层的设计

1.3数据管理层

从管理的角度来说,外界调用某些方法,你即可快速的响应操作,例如外界调用 open 方法,你就播放弹幕,调用Stop方法,你就关闭弹幕 接下来,你应该考虑以下几点。

到这里 , 我们设计方案基本完成,接下来我们可以开始编写代码。

2.代码实现

2.1数据层设计方案实现

我们需要构建一个 Barrage 类 ,我们每次去创建一个弹幕的时候都会 new Barrage,让他帮助我们生成一些弹幕属性。

export class Barrage {
  constructor(obj) {
  // 每次 new Barrage()  传入一个 后台返回的数据对象 obj
    const { barrageId, speed, level, top, jumpUrl, barrageContent, animationPlayState, ...args } = obj
    this.barrageId = barrageId; // id : 每条弹幕的唯一id
    this.speed = speed; // speed : 弹幕运行的速度,由外界控制 
    this.level = level; // level : 弹幕的层级 --> 弹幕可分为设计可分为 上下 1 , 1 两个层级 ,可决定弹幕的显示是全屏还是半屏显示
    this.top = top; //  top :弹幕生成的位置相对于 level 的层级 决定 ,相对于 Level 层级 盒子距离顶部的位置
    this.jumpUrl = jumpUrl; //  jumpUrl :点击弹幕需要跳转的链接
    this.barrageContent = barrageContent; // barrageContent : 弹幕的内容
    this.animationPlayState = ''; // 设计弹幕 是否可 点击暂停功能
    this.color = '#FFF' // 弹幕颜色
    this.args = args // 除去Barrage类之外的一些数据属性全部丢到这里,例如后台返回的数据
  }
}

2.2数据管理层设计方案实现

我们在这里实现了 , 弹幕的 增加,删除,初始化,重置,关闭 , 开启功能

1.实现弹幕开启功能

BarrageManager.js

export class BarrageManager {
constructor(barrageVue) {
    this.barrages = []; // 填弹幕的数组
    this.barragesIds = [] // 批量删除弹幕的数组id
    this.sourceBarrages = [] // 源弹幕数据
    this.timer = null //控制弹幕的开启和关
    this.barrageVue = barrageVue // 弹幕组件实例
    this.deleteCount = 0, // 销毁弹幕的总数
    this.lastDeleteCount = 0, // 最后可销毁的数量
    this.row = 0,
    this.count = 0
  }
  init(barrages) {
    this.sourceBarrages = barrages
    this.deleteCount = parseInt(this.sourceBarrages.length / deleteQuantity.FIFTY) // 计算可删除数量 
    this.lastDeleteCount = this.sourceBarrages.length % deleteQuantity.FIFTY // 计算 最后一次可删除数量
  }
   /**
   * 
   * @param {*} barrages 接收一个弹幕数组数据 
   * @description 循环创建 弹幕对象 ,将后台数据与 创建弹幕的属性结合 存入弹幕数组
   */
  loopCreateBarrage(barrages) {
    const { rows, createTime, crearteBarrageObject } = this.barrageVue
    let maxRows = rows / 2 // 最大的弹幕行数
    this.timer = setInterval(() => {
      for (let i = 0; i < 1; i++) {
        let barrageItem = barrages[this.count]
        if (this.row >= maxRows) { this.row = 0 } // 如果当前已经到了 最大的弹幕行数临界点则 回到第0 行弹道继续 创建
        if (!barrageItem) return clearInterval(this.timer) // 如果取不到了则证明没数据了 , 结束弹幕展示
        const item = crearteBarrageObject({ row: this.row, ...barrageItem }) // 添加对象到 弹幕数组中
        this.addBarrage(item)
        this.count++ // 用于取值 ,取了多少条
        this.row++ // 用于弹道
      }
    }, createTime * 1000);
  }
   /**
   * @param {*} barrages 传入一个弹幕数组数据 
   * @returns 无返回值
   * @description 调用 该方法 开始播放弹幕
   */
  open(barrages) {
    if (barrages.length === 0) return
    this.init(barrages)
    this.loopCreateBarrage(this.sourceBarrages)
    }
}

在这里我们初始化了一个 open 方法,并接收一个数组 ,并调用了 init 方法 去做初始化操作,并调用了 循环创建的方法,没 createTime 秒创建一条弹幕,加入到弹幕数组中。

2.连接视图层

2.3视图层 | 业务层设计方案实现

index.vue

<template>
  <div class="barrage">
    <div class="barrage-container" ref="barrageContainer">
      <div class="barrage-half-screen" ref="halfScreenContainer">
        <template v-for="item in barrageFiltering.level1">
          <barrage-item 
            :item="item" :class="{pausedAnimation : paused }" 
            :options='barrageTypeCallback(item)' 
            @destory="destoryBraageItem" :key="item.barrageId">
          </barrage-item>
        </template>
      </div>
      <div class="barrage-full-screen" v-if="fullScreen">
        <template v-for="item in barrageFiltering.level2">
          <barrage-item 
            :item="item" :class="{pausedAnimation : paused }"
            :options='barrageTypeCallback(item)'
            @destory="destoryBraageItem" :key="item.barrageId">
          </barrage-item>
        </template>
      </div>
    </div>
    <user-input ref="publishBarrage" v-if="openPublishBarrage" @onBlur="handleBlur">
      <template #user-operatio-right>
        <!-- 处理兼容性问题 ios 和 安卓 触发点击事件 -->
        <div class="send" @click="sendBarrage($event)" v-if="IOS">
          <slot name="rightRegion"></slot>
        </div>
        <div class="send" @mousedown="sendBarrage($event)" v-else>
          <slot name="rightRegion"></slot>
        </div>
      </template>
    </user-input>
  </div>
</template>
export default {
  created () {
    this.barrageManager = new BarrageManager(this)
  },
  mounted() {
    // 初始化弹幕渲染数据
    this.initBarrageRenderData();
  },
  data() {
    return {
      barrageManager : null,
      isClickSend: false,
      paused : false
    };
  },
  methods : {
    initBarrageRenderData() {
      this.barrageManager.open(this.barrages);
    },
  },
  computed : {
   barrageFiltering() {
      return {
        level1:
          this.barrageManager.barrages.filter(
            item => item.level === barrageLevel.LEVEL1
          ) || [],
        level2:
          this.barrageManager.barrages.filter(
            item => item.level === barrageLevel.LEVEL2
          ) || []
      };
    },
  }
}

视图层知识点回顾

在这里我们在弹幕组件创建的时候去创建了一个 弹幕管理对象,并且在挂载的时候去初始化了以下 弹幕渲染的数据,于是我们调用了 弹幕管理类open方法,这样当组件挂载时,就会去渲染 barrageFiltering 数据,这里我们是在管理类中拿到了管理类中循环创建的数据。

open 方法实现

到这里我们的弹幕的开启基本上已经完成了,可以看得出,如果你是这样设计的,你只需要在组件中调用管理类的一些方法,它就能帮你完成一些功能。

3.实现弹幕关闭功能

barrageManager.js

 class BarrageManager {
 constructor(barrageVue) {
    this.barrages = []; // 填弹幕的数组
    this.barragesIds = [] // 批量删除弹幕的数组id
    this.sourceBarrages = [] // 源弹幕数据
    this.timer = null //控制弹幕的开启和关
    this.barrageVue = barrageVue // 弹幕组件实例
    this.deleteCount = 0, // 销毁弹幕的总数
    this.lastDeleteCount = 0, // 最后可销毁的数量
    this.row = 0,
    this.count = 0
  }
 /**
   * @return 无返回值 
   * @description 调用close 方法 关闭弹幕
   */
  close() {
    clearInterval(this.timer)
    this.removeAllBarrage()
  }
   /**
   * @description 删除全部的弹幕数据
   */
  removeAllBarrage() {
    this.barrages = []
  }
 }

关闭功能知识点回顾

在这里我们可以看到,关闭弹幕的功能其实很简单,你只需要把开启弹幕时的定时器关闭,并且把弹幕数组数据清空就可以了

4.实现弹幕添加功能

index.vue

  addBarrage(barrageContent) {
      // 获取当前 定时器正在创建的 一行
      let currentRow = this.barrageManager.getRow();
      let row = currentRow === this.rows / 2 ? 0 : currentRow + 1;
      if (row === this.rows / 2) {
        row = 0;
      }
      let myBarrage = {
        row,
        barrageId: '1686292223004',
        barrageContent,
        style: this.style,
        type: "mySelf", // 用户自己发布的弹幕类型
        barrageCategory: this.userBarrageType
      };
      const item = this.crearteBarrageObject(myBarrage);
      this.barrageManager.addBarrage(item); // 数据准备好了 调用添加方法
      console.info("发送成功")
      this.barrageManager.setRow(row + 1);
    },

barrageManager.js

 class BarrageManager {
 constructor(barrageVue) {
    this.barrages = []; // 填弹幕的数组
    this.barragesIds = [] // 批量删除弹幕的数组id
    this.sourceBarrages = [] // 源弹幕数据
    this.timer = null //控制弹幕的开启和关
    this.barrageVue = barrageVue // 弹幕组件实例
    this.deleteCount = 0, // 销毁弹幕的总数
    this.lastDeleteCount = 0, // 最后可销毁的数量
    this.row = 0,
    this.count = 0
  }
   /**
   * 
   * @param {*} obj  合并完整的的弹幕对象
   * @param  {...any} args 开发者以后可能需要传递的剩余参数
   */
  addBarrage(obj, ...args) {
    const barrage = new Barrage(obj, ...args)
    this.barrages.push(barrage)
  }
 }

添加功能知识点回顾

在这里我们可以看到,添加的时候,我们 组件 只需要去调用 addBarrage 方法进行弹幕添加,并且在调用的过程中我们去 new Barrage 这个类 , 也就是我们之前准备好的 弹幕数据类 | 数据层设计

5.实现弹幕删除功能

class BarrageManager {
constructor(barrageVue) {
    this.barrages = []; // 填弹幕的数组
    this.barragesIds = [] // 批量删除弹幕的数组id
    this.sourceBarrages = [] // 源弹幕数据
    this.timer = null //控制弹幕的开启和关
    this.barrageVue = barrageVue // 弹幕组件实例
    this.deleteCount = 0, // 销毁弹幕的总数
    this.lastDeleteCount = 0, // 最后可销毁的数量
    this.row = 0,
    this.count = 0
  }
/**
   * 
   * @param {*} barrageId  // 入参 弹幕id
   * @returns 无返回值
   * @description 添加需要批量删除的 id 到 批量删除的栈中 barragesIds
   */
  addBatchRemoveId(barrageId) {
    this.barragesIds.push(barrageId)
    this.batchRemoveHandle()
  }
  /**
   * 
   * @param {*} start  你需要从第几位开始删除
   * @param {*} deleteCount  // 删除的总数是多少个
   * @returns 无返回值
   */
  batchRemoveBarrage(start, deleteCount) {
    if (this.barrages.length === 0) return
    this.barrages.splice(start, deleteCount)
  }
  batchRemoveId(start, deleteCount) {
    if (this.barragesIds.length === 0) return
    this.barragesIds.splice(start, deleteCount)
  }
  /**
   * @param {*} barrageId  弹幕 id 针对单个删除弹幕时 使用 
   */
  removeBarrage(barrageId) {
    let index = this.barrages.findIndex(item => item.barrageId === barrageId)
    this.barrages.splice(index, 1)
  }
  /**
   * @description 删除全部的弹幕数据
   */
  removeAllBarrage() {
    this.barrages = []
  }
  // 批量移除逻辑处理
  batchRemoveHandle() {
    if (this.deleteCount === 0 || this.deleteCount === 0) {
      if (this.barragesIds.length === this.lastDeleteCount) {
        this.batchRemoveBarrage(0, this.lastDeleteCount)
        this.batchRemoveId(0, this.lastDeleteCount)
      }
    } else {
      if (this.barragesIds.length === deleteQuantity.FIFTY) {
        this.batchRemoveBarrage(0, deleteQuantity.FIFTY)
        this.batchRemoveId(0, deleteQuantity.FIFTY)
        this.deleteCount--
      }
    }
  }
} 

删除功能知识点回顾

在这里我们可以看到,删除的时候我们把每一个弹幕id加入到了一个数组中 , 当 弹幕id数组长度达到我想要删除的数量的时候, 调用 splice 方法 执行批量删除操作,当数据发生更新,视图也会更新,这样我们只需要执行一次dom操作,不需要每一次删除弹幕更新dom,造成不必要的性能消耗。

6.实现弹幕重置功能

到这里,我相信你已经明白了我的设计,如果现在让你实现一个 重置弹幕方法 你会怎么做 ? 是不是只需要,调用一下 close 方法 , 然后再去 调用 open方法就可以了,ok 接下来我会将完整版代码 放入我的github仓库,小伙伴们可以去拉取 仓库链接,具体代码还需要小伙伴们自己从头阅读一次,这里只是说明了部分内容 , 阅读完成后 , 你就会彻底理解。

关于 barrageTypeCallback 函数

这个方法主要是可以解决弹幕样式定制的问题,你可以根据每个弹幕的类型 做不同的样式对象返回,我们会自动帮你渲染。

barrageTypeCallback ( {args} ) {
 const { barrageCategary } = args
 if(barrageCategary === 'type1'){
 retun {
 className : 'classOne',
 children : {
     show : false
     i : {
     showIcon : false,
     style : {
     color : 'red'
     }
     }
    }
   }
 }
 else{
 return { className : 'default' }
 }
}

以上就是基于Vue设计实现一个弹幕组件的详细内容,更多关于Vue弹幕组件的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文