使用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 初体验(建议学习jquery)
Apr 25 Javascript
jQuery获取当前对象标签名称的方法
Feb 07 Javascript
详解JavaScript正则表达式中的global属性的使用
Jun 16 Javascript
深入理解JS正则表达式---分组
Jul 18 Javascript
jQuery动态生成Bootstrap表格
Nov 01 Javascript
jacascript DOM节点——元素节点、属性节点、文本节点
Apr 18 Javascript
JavaScript数据类型的存储方法详解
Aug 25 Javascript
VsCode插件整理(小结)
Sep 14 Javascript
微信小程序之滚动视图容器的实现方法
Sep 26 Javascript
jQuery操作cookie的示例代码
Jun 05 jQuery
详解element-ui中el-select的默认选择项问题
Aug 02 Javascript
Jquery动态列功能完整实例
Aug 30 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
用 Composer构建自己的 PHP 框架之使用 ORM
2014/10/30 PHP
PHP加密解密字符串汇总
2015/04/26 PHP
PHP基本语法实例总结
2016/09/09 PHP
php版微信公众号自定义分享内容实现方法
2016/09/22 PHP
php查找字符串中第一个非0的位置截取
2017/02/27 PHP
php实现在线考试系统【附源码】
2018/09/18 PHP
如何编写高质量JS代码(续)
2015/02/25 Javascript
Js实现无刷新删除内容
2015/04/29 Javascript
jquery-tips悬浮提示插件分享
2015/07/31 Javascript
浅谈JS的基础类型与引用类型
2016/09/13 Javascript
微信小程序 实战小程序实例
2016/10/08 Javascript
URL的参数中有加号传值变为空格的问题(URL特殊字符)
2016/11/04 Javascript
详解VUE的状态控制与延时加载刷新
2017/03/27 Javascript
vue.js中父组件调用子组件的内部方法示例
2017/10/22 Javascript
使用webpack编译es6代码的方法步骤
2019/04/28 Javascript
vue+django实现一对一聊天功能的实例代码
2019/07/17 Javascript
node 解析图片二维码的内容代码实例
2019/09/11 Javascript
阿望教你用vue写扫雷小游戏
2020/01/20 Javascript
Vuex实现购物车小功能
2020/08/17 Javascript
Windows8下安装Python的BeautifulSoup
2015/01/22 Python
python 判断是否为正小数和正整数的实例
2017/07/23 Python
Python文本统计功能之西游记用字统计操作示例
2018/05/07 Python
详解python中Numpy的属性与创建矩阵
2018/09/10 Python
python七夕浪漫表白源码
2019/04/05 Python
python 实现将多条曲线画在一幅图上的方法
2019/07/07 Python
Python分析彩票记录并预测中奖号码过程详解
2019/07/09 Python
使用Html5实现异步上传文件,支持跨域,带有上传进度条
2016/09/17 HTML / CSS
前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)
2018/07/12 HTML / CSS
乌克兰在线药房:Аптека24
2019/10/30 全球购物
毕业生自我鉴定
2013/11/05 职场文书
母婴店促销方案
2014/03/05 职场文书
纪律教育学习月活动总结
2014/08/27 职场文书
会计主管竞聘书
2015/09/15 职场文书
如何用python反转图片,视频
2021/04/24 Python
SpringBoot连接MySQL获取数据写后端接口的操作方法
2021/11/02 MySQL
Zabbix对Kafka topic积压数据监控的解决方案
2022/07/07 Servers