# 利用 websocket 实现简单弹幕
# 1、前言
这里会一步一步实现一个弹幕系统,依赖上一篇的内容,建议先查看上一篇再来查看此篇。
# 2、先看个简单例子
bullet.html
<!DOCTYPE html> | |
<html lang="zh-CN"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<meta charset="utf-8"> | |
<title>斗鱼弹幕</title> | |
<style> | |
html, body { | |
font-size: 10px; | |
overflow: hidden; | |
margin: 0; | |
padding: 0; | |
} | |
#box { | |
width: 100%; | |
height: 100%; | |
} | |
#dm { | |
width: 100%; | |
height: 90vh; | |
background: #E8F1F5; | |
} | |
#dm span { | |
width: auto; | |
height: 3rem; | |
font-size: 2rem; | |
line-height: 2rem; | |
position: absolute; | |
white-space: nowrap; | |
} | |
#idDom { | |
width: 100%; | |
height: 10vh; | |
background: #666; | |
position: absolute; | |
bottom: 0; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
#content { | |
width: 50rem; | |
height: 10vh; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
.title { | |
font-size: 2.2px rein; | |
color: #fff; | |
line-height: #ccc; | |
} | |
.text { | |
width: 30rem; | |
height: 2.5rem; | |
border: none; | |
border-radius: .5rem; | |
font-size: 1.4rem; | |
margin: 0 .5rem; | |
padding: 0 1rem; | |
} | |
.btn { | |
width: 6rem; | |
height: 3rem; | |
border: none; | |
background: red; | |
color: #fff; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="box" id="box"> | |
<div id="dm"></div> | |
<div class="idDom" id="idDom"> | |
<div id="content"> | |
<p class="title">吐槽:</p> | |
<input type="text" class="text" id="text" placeholder="请输入你想说的话"/> | |
<button type="button" class="btn" id="btn">发射!</button> | |
</div> | |
</div> | |
</div> | |
<script langugae="javascript"> | |
var timer; | |
var btn = document.getElementById('btn'); | |
btn.onclick = function () { | |
addBarrage(); | |
} | |
document.onkeydown = function (evt) { | |
var event = evt || window.event; | |
if (event.keyCode == 13) { | |
addBarrage(); | |
} | |
} | |
var colors = ['#2C3E50', '#FF0000', '#1E87F0', '#7AC84B', '#FF7F00', '#9B39F4', '#FF69B4'];// 弹幕颜色库 | |
function addBarrage() { | |
clearInterval(timer); | |
var text = document.getElementById('text').value; | |
document.getElementById('text').value = ""; | |
var index = parseInt(Math.random() * colors.length); // 随机弹幕颜色 | |
var screenW = window.innerWidth; | |
var screenH = dm.offsetHeight; | |
var max = Math.floor(screenH / 40); | |
var height = 10 + 40 * (parseInt(Math.random() * (max + 1)) - 1); | |
var span = document.createElement('span'); | |
span.style.left = screenW + 'px'; | |
span.style.top = height + 'px'; | |
span.style.color = colors[index]; | |
span.innerHTML = text; | |
var dmDom = document.getElementById('dm'); | |
dmDom.appendChild(span); | |
timer = setInterval(move, 10); | |
} | |
function move() { | |
var arr = []; | |
var oSpan = document.getElementsByTagName('span'); | |
for (var i = 0; i < oSpan.length; i++) { | |
arr.push(oSpan[i].offsetLeft); | |
arr[i] -= 2; | |
oSpan[i].style.left = arr[i] + 'px'; | |
if (arr[i] < -oSpan[i].offsetWidth) { | |
var dmDom = document.getElementById('dm'); | |
dmDom.removeChild(dmDom.childNodes[0]); | |
} | |
} | |
} | |
</script> | |
</body> | |
</html> |
直接运行这个 html 页面你就能看到一个由 js 实现的弹幕,但是这个弹幕没有通信的作用。
# 3、部署 websocket 服务
上一篇编写的 websocket 服务,现在我们把他部署到服务器上,先打包然后再服务器上直接用 jar 运行,部署这一块自行解决,或者寻找百度。
如果不部署的话,就本地启用,访问的时候使用 http://loaclhost:8080/dreamlandWs 也行。 或者我提供一个线上的 websocket 服务:https://ws.yypdreamland.cn
前提你的服务也得是 https 的才能正常连接。
# 4、编写前端程序
接下来的可能就比较难了
# 1、准备好一个视频项目
这一步可能你需要花点心思,这里给一个图片示例:可以参考项目地址:https://yypdreamland.cn
红框中是我们需要绑定方法的
# 2、方法绑定
以下为示例,根据你项目中自己使用的前端框架自行绑定方法
方法体:
function openBullet() { | |
layer.prompt({title: '请输入你的名字'}, function (value, index, elem) { | |
if (value != null && value !== "" && value !== undefined) { | |
userId = value; | |
$("#open_bullet").hide(); | |
$("#close_bullet").show(); | |
// 连接 socket -- 当前的视频 id | |
// console.log(urlResult[3]) | |
connect(urlResult[3]); | |
} | |
layer.close(index); | |
}) | |
} | |
function closeBullet() { | |
// 断开 socket -- 当前的视频 id | |
$("#close_bullet").hide(); | |
$("#open_bullet").show(); | |
disconnect(); | |
} | |
function sendBullet() { | |
// 发送弹幕 | |
stompClient.send("/dreamlandBullet/bullet", {}, JSON.stringify({ | |
'bullet': $("#bulletMsg").val(), | |
'videoId': urlResult[3], | |
'user': userId | |
})); | |
} |
对应的 app.js 修改和新增
function connect(videoId) { | |
var socket = new SockJS('https://ws.yypdreamland.cn/dreamlandWs'); | |
stompClient = Stomp.over(socket); | |
stompClient.connect({}, function (frame) { | |
setConnected(true); | |
console.log('Connected: ' + frame); | |
stompClient.subscribe('/user/' + videoId + '/bullet', function (bullet) { | |
// showGreeting(bullet.body); | |
handleBullet(bullet.body); | |
}); | |
}); | |
} | |
function handleBullet(message) { | |
// 处理播放弹幕 | |
var msg = JSON.parse(message); | |
addBarrage(msg); | |
} | |
// 放弹幕 | |
var timer; | |
var colors = ['#2C3E50', '#FF0000', '#1E87F0', '#7AC84B', '#FF7F00', '#9B39F4', '#FF69B4'];// 弹幕颜色库 | |
function addBarrage(msg) { | |
clearInterval(timer); | |
var text = ""; | |
if (msg.user == userId) { | |
text = "我:" + msg.message | |
} else { | |
text = msg.user + ":" + msg.message | |
} | |
var index = parseInt(Math.random() * colors.length); // 随机弹幕颜色 | |
var dmDom = document.getElementById('screen'); | |
var screenW = dmDom.offsetWidth; | |
var screenH = dmDom.offsetHeight; | |
var max = Math.floor(screenH / 40); | |
var height = 10 + 40 * (parseInt(Math.random() * (max + 1)) - 1); | |
var span = document.createElement('span'); | |
span.style.left = screenW + 'px'; | |
span.style.top = height + 'px'; | |
span.style.color = colors[index]; | |
span.innerHTML = text; | |
span.setAttribute("bullet","yes") | |
dmDom.appendChild(span); | |
timer = setInterval(move, 10); | |
} | |
function move() { | |
var arr = []; | |
var oSpan = document.getElementById("screen").children; | |
for (var i = 0; i < oSpan.length; i++) { | |
arr.push(oSpan[i].offsetLeft); | |
arr[i] -= 1; | |
oSpan[i].style.left = arr[i] + 'px'; | |
if (arr[i] < -oSpan[i].offsetWidth) { | |
var dmDom = document.getElementById('screen'); | |
dmDom.removeChild(dmDom.childNodes[0]); | |
} | |
} | |
} |
以上如有不明白的地方可以发送邮件至我的邮箱:im.yyp@foxmail.com ;
# 3、效果展示
操作步骤:先打开弹幕,然后输入自己的名字(没有登录系统),然后就可以发送弹幕了。
以上为全部内容,多谢查阅!