使用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 相关文章推荐
onkeydown事件解决按回车键直接提交数据的需求
Apr 11 Javascript
JS+CSS实现感应鼠标渐变显示DIV层的方法
Feb 20 Javascript
详解JavaScript中shift()方法的使用
Jun 09 Javascript
对JavaScript客户端应用编程的一些建议
Jun 24 Javascript
基于JS实现的笛卡尔乘积之商品发布
May 13 Javascript
Jquery中map函数的用法
Jun 03 Javascript
js实现常用排序算法
Aug 09 Javascript
JavaScript 高性能数组去重的方法
Sep 20 Javascript
详解vue微信网页授权最终解决方案
Jun 16 Javascript
Vue.js+cube-ui(Scroll组件)实现类似头条效果的横向滚动导航条
Jun 24 Javascript
在pycharm中开发vue的方法步骤
Mar 04 Javascript
jQuery实现简单轮播图效果
Dec 27 jQuery
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
Netflix将与CLAMP、乙一以及冲方丁等6名知名制作人合伙展开原创动画计划!
2020/03/06 日漫
是否存在第一台收音机的说法
2021/03/01 无线电
木翼下载系统中说明的PHP安全配置方法
2007/06/16 PHP
完美解决PHP中文乱码
2009/11/26 PHP
PHP写的简单数字验证码实例
2017/05/23 PHP
thinkPHP框架乐观锁和悲观锁实例分析
2019/10/30 PHP
PHP PDO和消息队列的个人理解与应用实例分析
2019/11/25 PHP
JavaScript 加号(+)运算符号
2009/12/06 Javascript
JavaScript常用对象的方法和属性小结
2012/01/24 Javascript
js中eval详解
2012/03/30 Javascript
javascript中的toFixed固定小数位数 简单实例分享
2013/07/12 Javascript
获取表单控件原始(初始)值的方法
2013/08/21 Javascript
页面get请求 中文参数方法乱码问题的快速解决方法
2016/05/31 Javascript
jQuery基于函数重载实现自定义Alert函数样式的方法
2016/07/27 Javascript
微信小程序 wx:for的使用实例详解
2017/04/27 Javascript
Node.js  事件循环详解及实例
2017/08/06 Javascript
浅谈vue的踩坑路
2017/08/31 Javascript
Angularjs实现上传图片预览功能
2017/09/01 Javascript
Vuex提升学习篇
2018/01/11 Javascript
JS学习笔记之原型链和利用原型实现继承详解
2019/05/29 Javascript
vue实现打地鼠小游戏
2020/08/21 Javascript
解决Element中el-date-picker组件不回填的情况
2020/11/07 Javascript
[04:46]2018年度玩家喜爱的电竞媒体-完美盛典
2018/12/16 DOTA
Python中创建字典的几种方法总结(推荐)
2017/04/27 Python
在Pandas中DataFrame数据合并,连接(concat,merge,join)的实例
2019/01/29 Python
Django命名URL和反向解析URL实现解析
2019/08/09 Python
Python 实现取多维数组第n维的前几位
2019/11/26 Python
python删除指定列或多列单个或多个内容实例
2020/06/28 Python
浅析Python 抽象工厂模式的优缺点
2020/07/13 Python
简约控的天堂:The Undone
2016/12/21 全球购物
Amara美国站:英国高端家居礼品网站,世界各地的奢侈家具品牌
2017/07/26 全球购物
元旦联欢会主持词
2014/03/26 职场文书
淘宝客服专员岗位职责
2014/04/11 职场文书
2014年护士长工作总结
2014/11/11 职场文书
2014年医院个人工作总结
2014/12/09 职场文书
OpenCV实现反阈值二值化
2021/11/17 Java/Android