使用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面向对象的方式实现的弹出层效果代码
Jan 28 Javascript
分享精心挑选的12款优秀jQuery Ajax分页插件和教程
Aug 09 Javascript
jquery 删除cookie失效的解决方法
Nov 12 Javascript
javascript for-in有序遍历json数据并探讨各个浏览器差异
Nov 30 Javascript
JS实现的幻灯片切换显示效果
Sep 07 Javascript
解决Window10系统下Node安装报错的问题分析
Dec 13 Javascript
使用JavaScript实现alert的实例代码
Jul 06 Javascript
微信小程序使用Promise简化回调
Feb 06 Javascript
vue中render函数的使用详解
Oct 12 Javascript
微信小程序 函数防抖 解决重复点击消耗性能问题实现代码
Sep 12 Javascript
关于vue项目中搜索节流的实现代码
Sep 17 Javascript
小谈angular ng deploy的实现
Apr 07 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代码飞起来的40条小技巧(提升php效率)
2010/04/12 PHP
php读取富文本的时p标签会出现红线是怎么回事
2014/05/13 PHP
使用php批量删除数据库下所有前缀为prefix_的表
2014/06/09 PHP
php数字运算验证码的实现代码
2015/07/30 PHP
JavaScript单元测试ABC
2012/04/12 Javascript
js查错流程归纳
2012/05/04 Javascript
js函数的引用, 关于内存的开销
2012/09/17 Javascript
js QQ客服悬浮效果实现代码
2014/12/12 Javascript
玩转JavaScript OOP - 类的实现详解
2016/06/08 Javascript
AngularJs Understanding the Controller Component
2016/09/02 Javascript
简单实现JS上传图片预览功能
2017/04/14 Javascript
微信页面弹出键盘后iframe内容变空白的解决方案
2017/09/20 Javascript
深入理解Angular4订阅(Subscribe)与取消
2017/11/22 Javascript
Angular2实现组件交互的方法分析
2017/12/19 Javascript
为vue-router懒加载时下载js的过程中添加loading提示避免无响应问题
2018/04/03 Javascript
React组件重构之嵌套+继承及高阶组件详解
2018/07/19 Javascript
微信开发之企业付款到银行卡接口开发的示例代码
2018/09/18 Javascript
详解angular2.x创建项目入门指令
2018/10/11 Javascript
微信小程序如何修改本地缓存key中单个数据的详解
2019/04/26 Javascript
基于layui轮播图满屏是高度自适应的解决方法
2019/09/16 Javascript
javascript实现倒计时关闭广告
2021/02/09 Javascript
Python scikit-learn 做线性回归的示例代码
2017/11/01 Python
Python使用三种方法实现PCA算法
2017/12/12 Python
tensorflow: 查看 tensor详细数值方法
2018/06/13 Python
Python opencv实现人眼/人脸识别以及实时打码处理
2019/04/29 Python
python 含子图的gif生成时内存溢出的方法
2019/07/07 Python
opencv导入头文件时报错#include的解决方法
2019/07/31 Python
python 定义类时,实现内部方法的互相调用
2019/12/25 Python
HTML5上传文件显示进度的实现代码
2012/08/30 HTML / CSS
HTML5中的Article和Section元素认识及使用
2013/03/22 HTML / CSS
野兽派官方旗舰店:THE BEAST 野兽派
2016/08/05 全球购物
英国舒适型鞋履品牌:FitFlop
2017/05/17 全球购物
800字作文之大雪
2019/12/04 职场文书
Python中可变和不可变对象的深入讲解
2021/08/02 Python
vue如何实现关闭对话框后刷新列表
2022/04/08 Vue.js
利用正则表达式匹配浮点型数据
2022/05/30 Java/Android