使用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 图片上一张下一张链接效果代码
Mar 12 Javascript
jQuery淡入淡出元素让其效果更为生动
Sep 01 Javascript
js中的json对象详细介绍
Oct 29 Javascript
JS实现的数组全排列输出算法
Mar 19 Javascript
jquery实现横向图片轮播特效代码分享
Nov 19 Javascript
javascript基础知识分享之类与函数化
Feb 13 Javascript
JavaScript实现99乘法表及隔行变色实例代码
Feb 24 Javascript
完美解决jQuery 鼠标快速滑过后,会执行多次滑出的问题
Dec 08 Javascript
Node.js编写CLI的实例详解
May 17 Javascript
jackson解析json字符串,首字母大写会自动转为小写的方法
Dec 22 Javascript
使用Node.js实现一个多人游戏服务器引擎
Mar 13 Javascript
JS实现动态无缝轮播
Jan 11 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框架的理由
2015/09/26 PHP
PHP封装的数据库保存session功能类
2016/07/11 PHP
PHP实现简易blog的制作
2016/10/24 PHP
不错的JS中变量相关的细节分析
2007/08/13 Javascript
javascript检查日期格式的函数[比较全]
2008/10/17 Javascript
JavaScript学习笔记(十七)js 优化
2010/02/04 Javascript
Javascript获取HTML静态页面参数传递值示例
2013/08/18 Javascript
JS实现部分HTML固定页面顶部随屏滚动效果
2015/12/24 Javascript
jquery通过name属性取值的简单实现方法
2016/06/20 Javascript
JS实现表单验证功能(验证手机号是否存在,验证码倒计时)
2016/10/11 Javascript
jQuery ajaxForm()的应用
2016/10/14 Javascript
NodeJs实现定时任务的示例代码
2017/12/05 NodeJs
探索Vue高阶组件的使用
2018/01/08 Javascript
Layer弹出层动态获取数据的方法
2018/08/20 Javascript
移动端H5页面返回并刷新页面(BFcache)的方法
2018/11/06 Javascript
vue radio单选框,获取当前项(每一项)的value值操作
2020/09/10 Javascript
python实现K最近邻算法
2018/01/29 Python
Pycharm在创建py文件时,自动添加文件头注释的实例
2018/05/07 Python
pandas 将list切分后存入DataFrame中的实例
2018/07/03 Python
APIStar:一个专为Python3设计的API框架
2018/09/26 Python
python引用(import)某个模块提示没找到对应模块的解决方法
2019/01/19 Python
Python hashlib模块加密过程解析
2019/11/05 Python
python实现12306登录并保存cookie的方法示例
2019/12/17 Python
pytorch1.0中torch.nn.Conv2d用法详解
2020/01/10 Python
Pytorch .pth权重文件的使用解析
2020/02/14 Python
Jupyter安装链接aconda实现过程图解
2020/11/02 Python
SOA面试题:如何在SOA中实现松耦合
2013/07/21 面试题
宣传策划类求职信范文
2014/01/31 职场文书
医生辞职信范文
2015/03/02 职场文书
2015年医院护理部工作总结
2015/04/23 职场文书
证劵公司反洗钱宣传活动总结
2015/05/08 职场文书
2015暑期社会实践通讯稿
2015/07/18 职场文书
同学聚会祝酒词
2015/08/10 职场文书
2016年11月份红领巾广播稿
2015/12/21 职场文书
JS数组方法some、every和find的使用详情
2021/10/05 Javascript
改造DE1103三步曲
2022/04/07 无线电