使用canvas实现一个vue弹幕组件功能


Posted in Javascript onNovember 30, 2018

看B站时,对弹幕的实现产生了兴趣,一开始想到用css3动画去实现,后来感觉这样性能不是很好,查了下资料,发现可以用canvas实现,于是就摸索着写了一个简单的弹幕。

弹幕功能

  1. 支持动态添加弹幕
  2. 弹幕不重叠
  3. 自定义弹幕颜色

效果图

demo 

源码地址

使用canvas实现一个vue弹幕组件功能

前端框架选了比较熟悉的vuejs

弹幕滚动的基本思路就是通过定时器不断地改变弹幕的位置,时时重绘画布。

实现步骤

先加入一个canvas标签,这里有个注意点,关于设备像素比对canvas的影响,会出现绘图模糊。

<canvas width="600" height="600"></canvas> // 如果单纯这样写,canvas会出现模糊
<canvas width="600" height="600" style="width: 300px;height: 300px">
</canvas>
//为了不出现模糊,需要设置canvas的css宽高为上下文宽高的1/devicePixelRatio,
本文是对于devicePixelRatio:2的设备设置的,该值可从window.devicePixelRatio取得。
<canvas ref="hiddenCanvas" width="0" height="0" style="display: none">
</canvas> 
// 后面会用到

我们先定义一个数组来存放弹幕数据,一条弹幕信息,包括文本内容,x,y坐标位置,颜色,速度(可以是随机或者固定,为了计算简单,我们这里采用了固定的速度)

var dmArr = [];
var gap = 80; // 弹幕的上下间距
var hiddenCanvas = this.$refs.hiddenCanvas;
// 增加弹幕的方法
function pushDm(text, color) {
  let y = getY(); // 先确定跑道
  let x = 600; // 初始x坐标为canvas的右边界
  let delayWidth = 0; // 同跑道
  for (let i = 0, len = dmArr.length; i < len; i++) {
    let dm = dmArr[i];
    if (y === dm.y) { // 如果是同跑道,则往后排,设置一定的间隔,保证弹幕不会重叠;
      delayWidth += Math.floor(hiddenCanvas.getContext('2d').measureText(dm.text).width * 4 + 50);
    }  }
  dmArr.push({
    text: text,
    x: x + delayWidth,
    y: y,
    speed: 8,
    color: color || getColor()
  });
}
// 随机获得y坐标
function getY() {
  let range = Math.floor(600 / gap); // 跑道数量
  return Math.floor(Math.random() * range + 1) * gap;
}
// 随机获得颜色
function getColor() {
  return `${Math.floor(Math.random() * 16777215).toString(16)}`;
}
// 写一个for循环,初始化30条弹幕
for (let i = 0; i < 30; i++) {
  pushDm(`It's barrage ${i}`);
}

接下来设置一个20ms的定时器,实现弹幕滚动效果

var timer = null;
var ctx = this.$refs.canvas.getContext('2d');
function start(){
 timer = setInterval(() => {
  ctx.clearRect(0, 0, 600, 600); // 每次需要清空画布
  ctx.save();
  ctx.font = '30px Microsoft YaHei'; // 这里需要把字体大小设为需要显示的css大小的2倍(devicePixelRatio为2时)
  if (!dmArr.length) stop(); // 如果没有新弹幕了,就停止计时器
  for (let i = 0, len = this.dmArr.length; i < len; i++) {
    let dm = dmArr[i];
    let overRange = -ctx.measureText(dm.text).width * 2;
    dm.x -= dm.speed;
    if (dm.x < overRange) {
      dmArr.splice(i, 1); // 弹幕在画布中不可见时,从数组中移除该项
      continue;
    }
    ctx.fillStyle = `#${dm.color}`;
    ctx.fillText(dm.text, dm.x, dm.y);
  }
  ctx.restore();
 }, 20);
}
function stop() {
  clearInterval(timer);
  ctx.clearRect(0, 0, 600, 600);
}

我们还需要一个输入框,来实现手动添加弹幕功能

<input type="text" @keyup.enter="sent" v-model="dmInput" maxlength="20">

<button type="button" @click="sent">发表</button>
var dmInput = '';
var color = ''; // 可自定义弹幕的颜色
function sent() {
  if (!dmInput) return;
  stop();
  pushDm(dmInput, color);
  start();
  dmInput = '';
}

有待改进的地方和疑问?速度不恒定时,怎么保持弹幕不重叠视频弹幕是根据弹幕发送时间点来定位到视频的每一帧?如何实现?

总结

以上所述是小编给大家介绍的使用canvas实现一个vue弹幕组件功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
在JS中如何调用JSP中的变量
Jan 22 Javascript
JS批量修改PS中图层名称的方法
Jan 26 Javascript
jQuery原理系列-css选择器的简单实现
Jun 07 Javascript
Javascript中字符串和数字的操作方法整理
Jan 22 Javascript
jQuery移除或禁用html元素点击事件常用方法小结
Feb 10 Javascript
快速理解 JavaScript 中的 LHS 和 RHS 查询的用法
Aug 24 Javascript
javascript按钮禁用和启用的效果实例代码
Oct 29 Javascript
理顺8个版本vue的区别(小结)
Sep 17 Javascript
vue新vue-cli3环境配置和模拟json数据的实例
Sep 19 Javascript
微信小程序使用npm支持踩坑
Nov 07 Javascript
vue中使用vee-validator完成表单校验方案
Nov 01 Javascript
vue iview 隐藏Table组件里的某一列操作
Nov 13 Javascript
VUE基于NUXT的SSR 服务端渲染
Nov 30 #Javascript
Nuxt.js开启SSR渲染的教程详解
Nov 30 #Javascript
基于JavaScript实现每日签到打卡轨迹功能
Nov 29 #Javascript
Next.js项目实战踩坑指南(笔记)
Nov 29 #Javascript
js canvas实现二维码和图片合成的海报
Nov 19 #Javascript
详解@angular/cli 改变默认启动端口两种方式
Nov 29 #Javascript
js实现每日签到功能
Nov 29 #Javascript
You might like
PHP如何实现Unicode和Utf-8编码相互转换
2015/07/29 PHP
配置eAccelerator和XCache扩展来加速PHP程序的执行
2015/12/22 PHP
php基于curl主动推送最新内容给百度收录的方法
2016/10/14 PHP
Zend Framework入门教程之Zend_Config组件用法详解
2016/12/09 PHP
js function定义函数使用心得
2010/04/15 Javascript
jquery实现背景墙聚光灯效果示例分享
2014/03/02 Javascript
JS实现的用来对比两个用指定分隔符分割的字符串是否相同
2014/09/19 Javascript
JS实现转动随机数抽奖特效代码
2020/04/16 Javascript
全面解析JS字符串和正则表达式中的match、replace、exec等函数
2016/07/01 Javascript
详细谈谈javascript的对象
2016/07/31 Javascript
Vue2实现组件props双向绑定
2016/12/02 Javascript
JavaScript获取select中text值的方法
2017/02/13 Javascript
老生常谈javascript的面向对象思想
2017/08/22 Javascript
JavaScript实现图片本地预览功能【不用上传至服务器】
2017/09/20 Javascript
Javascript网页抢红包外挂实现分享
2018/01/11 Javascript
vue导出html、word和pdf的实现代码
2018/07/31 Javascript
Vue源码探究之状态初始化
2018/11/14 Javascript
详细讲解如何创建, 发布自己的 Vue UI 组件库
2019/05/29 Javascript
layui lay-verify form表单自定义验证规则详解
2019/09/18 Javascript
vue-socket.io接收不到数据问题的解决方法
2020/05/13 Javascript
[04:26]2014DOTA2西雅图国际邀请赛 总决赛TOPPLAY
2014/07/22 DOTA
Python出现segfault错误解决方法
2016/04/16 Python
【Python】Python的urllib模块、urllib2模块批量进行网页下载文件
2016/11/19 Python
Python SQLite3数据库日期与时间常见函数用法分析
2017/08/14 Python
python 搭建简单的http server,可直接post文件的实例
2019/01/03 Python
python实现读取excel文件中所有sheet操作示例
2019/08/09 Python
python 对任意数据和曲线进行拟合并求出函数表达式的三种解决方案
2020/02/18 Python
Python 读取xml数据,cv2裁剪图片实例
2020/03/10 Python
美国最大的在线寄售和旧货店:Swap.com
2018/08/27 全球购物
武汉世纪畅想数字传播有限公司 .NET笔试题
2015/06/13 面试题
班组长岗位职责
2014/03/03 职场文书
个人股份转让协议书范本
2015/01/28 职场文书
接收函
2019/04/22 职场文书
详解CSS伪元素的妙用单标签之美
2021/05/25 HTML / CSS
pytorch 运行一段时间后出现GPU OOM的问题
2021/06/02 Python
Go语言基础map用法及示例详解
2021/11/17 Golang