使用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 相关文章推荐
简略说明Javascript中的= =(等于)与= = =(全等于)区别
Apr 16 Javascript
jQuery之尺寸调整组件的深入解析
Jun 19 Javascript
js中function()使用方法
Dec 24 Javascript
js识别不同浏览器基于userAgent做判断
Jul 29 Javascript
基于jQuery实现的双11天猫拆红包抽奖效果
Dec 01 Javascript
Angular的Bootstrap(引导)和Compiler(编译)机制
Jun 20 Javascript
js实现背景图自适应窗口大小
Jan 10 Javascript
使用cropper.js裁剪头像的实例代码
Sep 29 Javascript
原生js实现简单的焦点图效果实例
Dec 14 Javascript
如何对react hooks进行单元测试的方法
Aug 14 Javascript
vue+node 实现视频在线播放的实例代码
Oct 19 Javascript
vue实现列表拖拽排序的功能
Nov 02 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遍历目录输出目录及其下的所有文件示例
2014/01/27 PHP
PHP中exec函数和shell_exec函数的区别
2014/08/20 PHP
thinkphp autoload 命名空间自定义 namespace
2015/07/17 PHP
php中替换字符串函数strtr()和str_repalce()的用法与区别
2016/11/25 PHP
PHP实现的mongoDB数据库操作类完整实例
2018/04/10 PHP
JavaScript中String和StringBuffer的速度之争
2010/04/01 Javascript
jQuery之浮动窗口实现代码(两种方法)
2010/09/08 Javascript
为radio类型的INPUT添加客户端脚本(附加实现JS来禁用onClick事件思路代码)
2010/11/11 Javascript
合并table相同单元格的jquery插件分享(很精简)
2011/06/20 Javascript
javascript实现简单的Map示例介绍
2013/12/23 Javascript
使用javascript为网页增加夜间模式
2014/01/26 Javascript
用js一次改变多个input的readonly属性值的方法
2014/06/11 Javascript
Linux下编译安装php libevent扩展实例
2015/02/14 Javascript
jQuery中判断对象是否存在的方法汇总
2016/02/24 Javascript
Node.js制作简单聊天室
2017/01/12 Javascript
移动端如何用下拉刷新的方式实现上拉加载
2018/12/10 Javascript
vue+element项目中过滤输入框特殊字符小结
2019/08/07 Javascript
详解elementUI中input框无法输入的问题
2020/04/27 Javascript
简单谈谈python中的多进程
2016/11/06 Python
利用python将图片转换成excel文档格式
2017/12/30 Python
Python中实现最小二乘法思路及实现代码
2018/01/04 Python
python实战教程之自动扫雷
2018/07/13 Python
python特性语法之遍历、公共方法、引用
2018/08/08 Python
pandas-resample按时间聚合实例
2019/12/27 Python
使用 tf.nn.dynamic_rnn 展开时间维度方式
2020/01/21 Python
基于python获取本地时间并转换时间戳和日期格式
2020/10/27 Python
五款漂亮的纯CSS3动画按钮的实例教程
2014/11/21 HTML / CSS
大学生学业生涯规划
2014/01/05 职场文书
关于廉洁的广播稿
2014/01/30 职场文书
资源工程专业毕业生求职信
2014/02/27 职场文书
个人查摆问题整改措施
2014/10/04 职场文书
三严三实学习心得体会
2014/10/13 职场文书
2014年政教处工作总结
2014/12/20 职场文书
JavaScript实现队列结构过程
2021/12/06 Javascript
Python selenium绕过webdriver监测执行javascript
2022/04/12 Python
css样式important规则的正确使用方式
2022/06/10 HTML / CSS