使用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 相关文章推荐
jquery 仿QQ校友的DIV模拟窗口效果源码
Mar 24 Javascript
js控制页面控件隐藏显示的两种方法介绍
Oct 09 Javascript
简单的两种Extjs formpanel加载数据的方式
Nov 09 Javascript
node+experss实现爬取电影天堂爬虫
Nov 20 Javascript
如何用JS/HTML将时间戳转换为“xx天前”的形式
Feb 06 Javascript
使用Bootstrap + Vue.js实现表格的动态展示、新增和删除功能
Nov 27 Javascript
vue2.0 根据状态值进行样式的改变展示方法
Mar 13 Javascript
js实现input密码框显示/隐藏功能
Sep 10 Javascript
微信 jssdk 签名错误invalid signature的解决方法
Jan 14 Javascript
js序列化和反序列化的使用讲解
Jan 19 Javascript
vue框架下部署上线后刷新报404问题的解决方案(推荐)
Apr 03 Javascript
Angular+ionic实现折叠展开效果的示例代码
Jul 29 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中文件读、写、删的操作(PHP中对文件和目录操作)
2012/03/06 PHP
php启动时候提示PHP startup的解决方法
2013/05/07 PHP
php使用mb_check_encoding检查字符串在指定的编码里是否有效
2013/11/07 PHP
PHP实现生成数据字典功能示例
2018/05/24 PHP
PHP数组array类常见操作示例
2020/05/15 PHP
仅Firefox中链接A无法实现模拟点击以触发其默认行为
2011/07/31 Javascript
Javascript实现的常用算法(如冒泡、快速、鸽巢、奇偶等)
2014/04/29 Javascript
js实现鼠标悬停图片上时滚动文字说明的方法
2015/02/17 Javascript
jQuery中each()、find()和filter()等节点操作方法详解(推荐)
2016/05/25 Javascript
js实现定时进度条完成后切换图片
2017/01/04 Javascript
js实现图片360度旋转
2017/01/22 Javascript
jQuery插件HighCharts绘制2D带Label的折线图效果示例【附demo源码下载】
2017/03/08 Javascript
JS中IP地址与整数相互转换的实现代码
2017/04/10 Javascript
bootstrap+jQuery实现的动态进度条功能示例
2017/05/25 jQuery
解决iview多表头动态更改列元素发生的错误的方法
2018/11/02 Javascript
Element-UI中关于table表格的那些骚操作(小结)
2019/08/15 Javascript
8个非常实用的Vue自定义指令
2020/12/15 Vue.js
Python 正则表达式入门(中级篇)
2016/12/07 Python
python selenium UI自动化解决验证码的4种方法
2018/01/05 Python
详解Python如何生成词云的方法
2018/06/01 Python
python调用百度语音识别实现大音频文件语音识别功能
2018/08/30 Python
Python设计模式之模板方法模式实例详解
2019/01/17 Python
在Keras中利用np.random.shuffle()打乱数据集实例
2020/06/15 Python
HTML5中的拖放实现详解
2017/08/23 HTML / CSS
英格兰橄榄球商店:England Rugby Store
2016/12/17 全球购物
世嘉游戏英国官方商店:SEGA Shop UK
2019/09/20 全球购物
传播学专业毕业生自荐信
2013/11/04 职场文书
事业单位请假制度
2014/01/13 职场文书
幼儿园课题方案
2014/06/09 职场文书
国际经济贸易专业自荐信
2014/06/13 职场文书
擅自离岗检讨书
2014/09/12 职场文书
大学生自荐材料范文
2014/12/30 职场文书
2015年清明节活动总结
2015/02/09 职场文书
煤矿隐患排查制度
2015/08/05 职场文书
JavaScript 防篡改对象的用法示例
2021/04/24 Javascript
SQL 窗口函数实现高效分页查询的案例分析
2021/05/21 SQL Server