基于原生js实现主流弹幕的所有功能
原生js实现弹幕效果原理 二
距离写实现原理一有很长一段时间了,因为好像没什么人看,所以我就不太想写原理二,为了不食言,我还是坚持做完这个系列吧
下面介绍的就是目前主流直播弹幕网站的弹幕实现方式,包括弹幕指定暂停,点赞,举报功能.
首先来看一张实现动图
barrage-2 原理简介
- 动画效果使用css3中的 transition 属性实现
- 只有transition是远远不够的,因为transition需要主动触发,但是一般网上常见的简单的触发方式,就是 定义css样式的:hover或者:focus属性,指定用户的某一个活动主动触发transition,这显然是无法实现弹幕自动化效果的。因此,可以想到使用js触发。css触发说到底也就是当满足某种条件时,替换dom元素的class样式。
- 知道原理以后我们要做的就是,在适当的时机给弹幕dom添加上class或者移除class,在js里这是非常简单的,dom.classList.add("xxx")实现添加class,dom.classList.remove("xxx")移除class.
- 上面强调的 适当 这个词大有文章,
众所周知,js是一个单线程编程语言,可能有些人被setInterval和setTimeOut函数误导,以为是js引擎新开了一个线程去处理定时功能,但实际上,js引擎所做仅仅只是,1.将计时任务放到一个带有优先级的事件队列中 2.然后一个一个的执行事件 - 上面说了js引擎是单线程按队列顺序执行事件,但每个事件之间不可避免的会有间隔时间,在这个间隔时间里js引擎是空闲的,当js引擎空闲时,就是GUI绘制引擎工作的时间了,GUI引擎做的工作就是渲染dom。即是说,并不是说js刚改变class,dom元素的样式就会刷新,中间有一个间隔时间,这个间隔时间就是GUI引擎在等待js引擎空闲,具体的细节你们可以去https://blog.csdn.net/qq_36995542/article/details/80007381看看。
当初我把我对js单线程的理解发到一个前端群的时候,有个25仔说这已经达到了月薪2万的前端水准,老子信了他的鬼。。。。。
------------- - 锐客网
测试弹幕.....
文章图片
0
黑色
红色
绿色
白色
我实在是不知道怎么让html代码在不被解析的情况下保持缩进...
html代码没什么好说的,连这个都看不懂的话,下面的基本也没戏了。
重头戏js源码
- js这门语言的特点就是: 它的语义宽松,这也就导致了很多的js代码写出来显得杂乱无章,比如我这个。但是用熟练了以后,你就会发现它越用越上瘾。
"use strict";
var barrageContent = document.getElementsByClassName("barrage-content")[0];
// var rect = barrageContent.getBoundingClientRect();
/**
* 弹道
* @type {HTMLCollectionOf}
*/
var barrageRoad = document.getElementsByClassName("barrage-road");
var rangeValue = https://www.it610.com/article/20;
//字体大小 预设值var sliderHandle = document.getElementsByClassName("range-slider-handle")[0];
//字体调节滑块
var slider = document.getElementsByClassName("range-slider")[0];
var sliderRect = slider.getBoundingClientRect();
var sliderFill = document.getElementsByClassName("range-slider-fill")[0];
//滑过区域
var textPreview = document.getElementsByClassName("text-preview")[0];
//预览字体区var content = document.getElementsByClassName("comment-input")[0];
//弹幕输入框
var speedNum = document.getElementsByClassName("speed-selector")[0];
//弹幕速度
var color = document.getElementsByName("colorSelected");
//弹幕颜色选择器
var colorSelected = "white";
//被选择颜色 预设值var transitionEvent = whichTransitionEvent();
//判断浏览器内核类型var index = 1;
//数据库弹幕表分页页码var deviceType = goPAGE();
var I = 0;
//右键弹幕的id
sliderHandle.style.left = "0px";
/**
* 测试用数据 数据格式,我下面的源码获取数据是用的我自己建的后台,如果你只是想要一个单机版的话,直接添加下面数组里的初始化数据就行,每个字段都要。
* @type {*[]}
*/
var barrageData_2 = [
{
"barrageId": 1,
"content": "第二条弹幕.............",
"color": "red",
"speed": 16,
"textSize": 20,
"road": 0,
"starNum":0
}
];
barrageData_2 = barrageData_2.concat();
/**
* 初始化操作自执行函数
*/
(function () {
for (var i = 0;
i < barrageData_2.length;
i++) {
barrageData_2[i]["road"] = i % barrageRoad.length;
}
console.log("screen-size", screen.width, screen.height);
var that = this;
var timer = setInterval(function (args) {
if (barrageData_2.length <= 0) {
console.log("barrageData:", barrageData_2);
regularGetBarrage();
return;
}
sendBarrage(barrageData_2[0]["barrageId"], barrageData_2[0]["content"], barrageData_2[0]["color"], barrageData_2[0]["speed"], barrageData_2[0]["textSize"], barrageData_2[0]["road"]);
barrageData_2.splice(0, 1);
}, 1000);
})();
window.onload = function (ev) {
document.getElementsByClassName("menu-item")[0].onclick = report;
//TODO
}/**
* 鼠标指定弹幕事件函数
* @param event
*/
function onMouseIn(event) {
var barrage = event.valueOf();
var computeStyle = window.getComputedStyle(barrage), left = computeStyle.getPropertyValue("left");
barrage.style.left = left;
barrage.classList.remove("barrage-active");
}/**
* 鼠标离开弹幕事件函数
* @param event
*/
function onMouseLeave(event) {
var barrage = event.valueOf();
barrage.classList.add("barrage-active");
}/**
* 弹幕点击事件
* @param event
*/
function mouseClicked(event) {
var barrage = event.valueOf();
barrage.classList.add("barrage-clicked");
barrage.childNodes[1].setAttribute("src", "/pic/star-active.png");
barrage.childNodes[3].innerHTML = parseInt(barrage.childNodes[3].innerHTML) + 1;
star(barrage);
}/**
* 弹幕发送处理函数
* @param index
* @param content 弹幕内容
* @param colorSelected 选择的颜色
* @param speedNum 弹幕速度
* @param rangeValue 字体大小
* @param roadNum 弹道
*/
function sendBarrage(barrageId, content, colorSelected, speedNum, rangeValue, roadNum) {var newBarrage = document.createElement("span");
if (content === "") {
return;
}newBarrage.classList.add("barrage");
newBarrage.style.setProperty("color", colorSelected);
newBarrage.style.transitionDuration = speedNum + "s";
newBarrage.style.webkitTransitionDuration = speedNum + "s";
newBarrage.style.setProperty("font-size", rangeValue + "px");
newBarrage.innerHTML = content + "" +
""+barrageData_2[0]["starNum"]+"";
newBarrage.onmouseenter = function (ev) {
onMouseIn(this);
};
newBarrage.onmouseleave = function (ev) {
onMouseLeave(this);
};
if (deviceType === "pc"){
newBarrage.onclick = function (ev) {
var ul = document.getElementsByClassName("right-menu-ul")[0];
ul.style.display = "none";
mouseClicked(this);
};
} else {
newBarrage.ontouchend = function (ev) {
var ul = document.getElementsByClassName("right-menu-ul")[0];
ul.style.display = "none";
mouseClicked(this);
}
}newBarrage.oncontextmenu = function (ev) {
var ul = document.getElementsByClassName("right-menu-ul")[0];
// console.log("contextmenu", ev.currentTarget.valueOf().childNodes);
event.preventDefault();
//TODO 奇迹的用法
I = barrageId;
ul.style.display = "block";
ul.style.left = event.clientX + 10 + "px";
ul.style.top = event.clientY + 10 + "px";
};
//TODO 备注,dom初始化的时机
barrageRoad[roadNum].appendChild(newBarrage);
setTimeout(function () {
newBarrage.classList.add("barrage-active");
},50);
newBarrage.addEventListener(transitionEvent, function (evt) {
// console.log(this);
this.parentNode.removeChild(this);
// barrageData_2.splice(0, 1);
console.log("----------------------transitionEnd事件触发一次---------------");
});
}/**
* 滑块鼠标按下事件函数
* @param event
*/
if (deviceType === "pc"){
sliderHandle.onmousedown = function (event) {
var that = this;
var oldX = event.clientX;
var left = parseInt(that.style.left);
document.onmousemove = function (ev) {
var x = ev.clientX - oldX;
that.style.left = left + x + "px";
rangeValue = https://www.it610.com/article/Math.ceil((parseInt(that.style.left) / sliderRect.width) * 40) + 1;
if (parseInt(that.style.left) < 0) {
that.style.left ="0";
rangeValue = https://www.it610.com/article/10;
}
if (parseInt(that.style.left)> sliderRect.width) {
that.style.left = sliderRect.width - 10 + "px";
rangeValue = https://www.it610.com/article/50;
}
sliderFill.style.width = that.style.left;
textPreview.style.fontSize = rangeValue +"px";
console.log("rangeValue: ", rangeValue);
};
document.onmouseup = function (ev) {
document.onmouseup = null;
document.onmousemove = null;
}
};
} else {
sliderHandle.ontouchstart = function (event) {
var that = this;
var oldX = event.clientX;
var left = parseInt(that.style.left);
document.ontouchmove = function (ev) {
var x = ev.clientX - oldX;
that.style.left = left + x + "px";
console.log("left", that.style.left);
rangeValue = https://www.it610.com/article/Math.ceil((parseInt(that.style.left) / sliderRect.width) * 40) + 1;
if (parseInt(that.style.left) < 0) {
that.style.left ="0";
rangeValue = https://www.it610.com/article/10;
}
if (parseInt(that.style.left)> sliderRect.width) {
that.style.left = sliderRect.width - 10 + "px";
rangeValue = https://www.it610.com/article/50;
}
sliderFill.style.width = that.style.left;
textPreview.style.fontSize = rangeValue +"px";
console.log("rangeValue: ", rangeValue);
};
document.ontouchend = function (ev) {
document.ontouchend = null;
document.ontouchmove = null;
}
};
}/**
* 发送弹幕按钮点击事件响应函数
*/
function addBarrageData() {
var item = {
"content": "",
"color": "red",
"speed": 16,
"textSize": 20,
"road": 0,
"starNum": 0
};
var content_1 = content.value;
item["speed"] = speedNum.value;
item["textSize"] = rangeValue;
item["road"] = Math.floor(Math.random() * barrageRoad.length);
content_1 = contentFilter();
item["content"] = content_1;
console.log("content: ", content_1);
for (var i = 0;
i.*?<\/.*?>/g, '[非法字段]');
content_1 = content_1.replace(/
css代码
【基于原生js实现主流弹幕的所有功能】这个我就放github上算了,不然篇幅实在是太长了。
https://github.com/TomShiDi/barrage-website
下一篇文章预告
实现一个基于springboot框架的注解方法跟踪小框架
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- MybatisPlus使用queryWrapper如何实现复杂查询
- python学习之|python学习之 实现QQ自动发送消息
- 基于|基于 antd 风格的 element-table + pagination 的二次封装
- 孩子不是实现父母欲望的工具——林哈夫
- opencv|opencv C++模板匹配的简单实现
- Node.js中readline模块实现终端输入
- java中如何实现重建二叉树
- NeuVector 会是下一个爆款云原生安全神器吗()