使用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 相关文章推荐
js中的escape及unescape函数的php实现代码
Sep 04 Javascript
善用事件代理,警惕闭包的性能陷阱。
Jan 20 Javascript
Javascript 绘制 sin 曲线过程附图
Aug 21 Javascript
jquery实现动静态条形统计图
Aug 17 Javascript
jQuery实现垂直半透明手风琴特效代码分享
Aug 21 Javascript
Highcharts学习之数据列
Aug 03 Javascript
从对象列表中获取一个对象的方法,依据关键字和值
Sep 20 Javascript
vue.js 使用axios实现下载功能的示例
Mar 05 Javascript
javascript异步编程的六种方式总结
May 17 Javascript
layui框架与SSM前后台交互的方法
Sep 12 Javascript
Vue项目开发常见问题和解决方案总结
Sep 11 Javascript
vue项目中的支付功能实现(微信支付和支付宝支付)
Feb 18 Vue.js
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面向对象分析设计的61条军规小结
2010/07/17 PHP
PHP表单递交控件名称含有点号(.)会被转化为下划线(_)的处理方法
2013/01/06 PHP
php session的锁和并发
2016/01/22 PHP
PHP+AJAX 投票器功能
2017/11/11 PHP
[原创]PHP global全局变量经典应用与注意事项分析【附$GLOBALS用法对比】
2019/07/12 PHP
php7连接MySQL实现简易查询程序的方法
2020/10/13 PHP
jQuery把表单元素变为json对象
2013/11/06 Javascript
js生成随机数之random函数随机示例
2013/12/20 Javascript
在百度知道团队中快速审批新成员的js脚本
2014/02/02 Javascript
JavaScript新窗口与子窗口传值详解
2014/02/11 Javascript
jquery中each遍历对象和数组示例
2014/08/05 Javascript
js制作简单的音乐播放器的示例代码
2017/08/28 Javascript
JS实现DOM删除节点操作示例
2018/04/04 Javascript
Vue模板语法中数据绑定的实例代码
2019/05/17 Javascript
vue使用@scroll监听滚动事件时,@scroll无效问题的解决方法详解
2019/10/15 Javascript
py2exe 编译ico图标的代码
2013/03/08 Python
python对配置文件.ini进行增删改查操作的方法示例
2017/07/28 Python
全面了解Nginx, WSGI, Flask之间的关系
2018/01/09 Python
用python实现将数组元素按从小到大的顺序排列方法
2018/07/02 Python
pandas.DataFrame选取/排除特定行的方法
2018/07/03 Python
python 图像判断,清晰度(明暗),彩色与黑白实例
2020/06/04 Python
Python threading模块condition原理及运行流程详解
2020/10/05 Python
使用Django的JsonResponse返回数据的实现
2021/01/15 Python
Pytorch - TORCH.NN.INIT 参数初始化的操作
2021/02/27 Python
Html5新标签解释及用法
2012/02/17 HTML / CSS
美国著名童装品牌:OshKosh B’gosh
2016/08/05 全球购物
Parfume Klik丹麦:香水网上商店
2018/07/10 全球购物
草莓网中国:StrawberryNet中国
2020/08/17 全球购物
一套.net面试题及答案
2016/11/02 面试题
高级Java程序员面试题
2016/06/23 面试题
职称自我鉴定
2013/10/15 职场文书
医科学校毕业生自荐信
2013/11/09 职场文书
网络教育自我鉴定
2014/02/04 职场文书
2014年安全生产目标责任书
2014/07/23 职场文书
入党心得体会
2019/06/20 职场文书
聊聊mysql都有哪几种分区方式
2022/04/13 MySQL