jQuery 简洁版
需求
- 输入框输入点击,生成随机样式的span
- span弹幕从右往左运动
实现
输入框输入点击,生成随机样式的span
var barrageVal = $('input').val();
var widthSize = $('.barrageShow').width();
var rightVal = widthSize;
var heightSize = $('.barrageShow').height();
var topVal = Math.random() * heightSize;
var colorSize = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
var colorVal = '#' + colorSize[Math.ceil(Math.random() * 16)] + colorSize[Math.ceil(Math.random() * 16)] +
colorSize[Math.ceil(Math.random() * 16)] + colorSize[Math.ceil(Math.random() * 16)] + colorSize[
Math.ceil(Math.random() * 16)] + colorSize[Math.ceil(Math.random() * 16)];
var fontsizeVal = Math.ceil(Math.random() * 20 + 12);
var speedVal = Math.random() * 5000 + 10000;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
span弹幕从右往左运动
if (barrageVal.trim()) {
var dom = document.createElement('span');
document.querySelector('.barrageShow').appendChild(dom);
$(dom).html(barrageVal)
.css({
color: colorVal,
fontSize: fontsizeVal,
top: topVal
})
.animate({right: rightVal}, speedVal , function () {
$(dom).fadeOut();
});
}
缺陷
只能实现无刷新弹幕
改进思路
数据分离出来:
前台获取的数据, 先保存到后台;
前台要显示, 再从后台调取.
JSON+Ajax版 实现简单同步
需求
- 输入框输入点击,生成随机样式的span
- span数据给后台将数据保存后
- 前台调取后台数据信息,完成span弹幕从右往左运动
实现
输入框输入点击,生成随机样式的span
var timeVal = new Date().getTime();
var topPer = parseInt(Math.random() * heightSize) / heightSize;
span数据给后台将数据保存后,并返回给前台
$.ajax({
url: './data/getData.php',
type: 'post',
data: {
value: barrageVal,
timetemp: timeVal,
color: colorVal,
fontSize: fontsizeVal,
top: topPer,
speed: speedVal
},
success: function (backData) {
console.log(backData);}
<--对应的getData.php-->
<?php
$value = addslashes($_POST['value']);
$timetemp = addslashes($_POST['timetemp']);
$color = addslashes($_POST['color']);
$fontSize = addslashes($_POST['fontSize']);
$top = addslashes($_POST['top']);
$speed = addslashes($_POST['speed']);
$str = '[';
$obj = chop(ltrim(file_get_contents('./backData/barrage.json'),"[,") ,"]");
file_put_contents('./backData/barrage.json',$obj);
file_put_contents('./backData/barrage.json',',{"value":"'.$value.'","timetemp":"'.$timetemp.'","color":"'.$color.'","fontSize":"'.$fontSize.'","top":"'.$top.'","speed":"'.$speed.'","wSize":"'.$wSize.'"}',FILE_APPEND);
$obj = ltrim(file_get_contents('./backData/barrage.json'),",");
$str = $str.$obj;
$str =$str.']';
file_put_contents('./backData/barrage.json',$str);
echo 'success!';
?>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
前台根据数据信息,完成span弹幕从右往左运动
其中一个思路要改变: 之前让每一个span弹幕自行animate运动;
现在则是设置定时器, 让barrageShow上的span弹幕改变right定位, 来模拟运动.
setInterval(function () {
$.ajax({
url: './data/showData.php',
data: {},
success: function (backData) {
$('.barrageShow').html('');
var spanArr = JSON.parse(backData);
var rightSize = $('.barrageShow').width();
var dom = [];
for (var i = 0; i < spanArr.length; i++) {
var topVal = spanArr[i].top * $('.barrageShow').height();
var rightVal = (new Date().getTime() - spanArr[i].timetemp) /spanArr[i].speed *rightSize - rightSize;
if (rightVal > rightSize) continue;
dom[i] = document.createElement('span');
$('.barrageShow').append(dom[i]);
$(dom[i]).html(spanArr[i].value).css({
color: spanArr[i].color,
fontSize: spanArr[i].fontSize,
top: topVal,
right: rightVal
})
}
}
})
}, 10);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
<--对应的showData.php-->
<?php
echo file_get_contents('./backData/barrage.json');
?>
缺陷
能实现刷新数据不丢失
但不能实现多屏同步效果
改进思路
数据分离出来:
之前保存在json文件中,改进为保存在mysql数据库;
时间戳:
这个概念非常重要,因为多屏同步, 每一个客户端的时间是不同的. 所以需要在加载网页的时候就要获取客户端的时间与服务器的时间来计算时间差;
将每一个客户端的时间都转换为服务器的时间. 这样每一个客户端发出的请求就都是以服务器为标准, 看上去, 客户端发布一条span弹幕, 每一个打开页面的客户端都可以同步看见.
Mysql+Ajax版 实现简单同步
需求
- 输入框输入点击,生成随机样式的span
- span数据给后台将数据保存后
- 前台调取后台数据信息,完成span弹幕从右往左运动
实现
增加时间差概念
var cilentTime = new Date().getTime();
var timeDif;
$.ajax({
url: './data/getCilentTime.php',
data: {},
success: function (backData) {
timeDif = cilentTime - backData*1000;
}
})
<--对应的getCilentTime.php-->
<?php
date_default_timezone_set("Asia/Shanghai");
$now = time();
echo $now;
?>
输入框输入点击,生成随机样式的span
span数据给后台将数据保存后,并返回给前台
$.ajax({
url: './data/getData.php',
type: 'post',
data: {
value: barrageVal,
timetemp: timeVal,
timeDif: timeDif,
color: colorVal,
fontSize: fontsizeVal,
top: topPer,
speed: speedVal
},
success: function (backData) {
console.log(backData);}
<--对应的getData.php-->
<?php
include './sql_login.php';
$value = addslashes($_POST['value']);
$timetemp = $_POST['timetemp'];
$timeDif = $_POST['timeDif'];
$color = addslashes($_POST['color']);
$fontSize = $_POST['fontSize'];
$topPer = $_POST['topPer'];
$speed = $_POST['speed'];
$sql="INSERT INTO barrage ( value, timetemp, timeDif, color, fontSize, topPer, speed, wSize, hSize)
VALUES
('$value',$timetemp,$timeDif,'$color',$fontSize,$topPer,$speed,$wSize,$hSize)";
if (!mysql_query($sql,$con)){
die('Error: ' . mysql_error());
}
echo '{"status":"ok"}';
mysql_close($con)
?>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
前台根据数据信息,完成span弹幕从右往左运动
其中又一个思路要改变: 最之前让每一个span弹幕自行animate运动;
第二版则是设置定时器, 让barrageShow上的span弹幕改变right定位, 来模拟运动;
现在是让加载页面是执行第一版的逻辑; 之后barrageShow不断请求ajax数据, 有数据则添加到弹屏执行第一版的span弹幕逻辑
var currentId = 0;
setTimeout(show, 50);
setInterval(add, 100);
function show() {
var nowTime = new Date().getTime();
$.ajax({
url: './data/showData.php',
data: {
timeDif: timeDif,
nowTime: nowTime,
barrageId: currentId
},
success: function (backData) {
var spanArr = JSON.parse(backData)['list'];
currentId = JSON.parse(backData)['lastId'];
var rightSize = $('.swiper-container').width();
var heightSize = $('.swiper-container').height();
var dom = [];
for (var i = 0; i < spanArr.length; i++) {
var topVal = spanArr[i].topPer * heightSize;
var rightVal = getRight();
dom[i] = document.createElement('span');
$('.barrageShow').append(dom[i]);
$(dom[i]).html(spanArr[i].value).css({
color: spanArr[i].color,
fontSize: spanArr[i].fontSize + "px",
top: topVal + "px",
right: rightVal + "px"
})
.animate({
right: rightSize + "px"
}, 10000);
function getRight() {
var timeXD = nowTime - timeDif + parseInt(spanArr[i].timeDif);
return (timeXD - spanArr[i].timetemp) / spanArr[i].speed * rightSize - rightSize
}
}
}
});
}
function add() {
var nowTime = new Date().getTime();
$.ajax({
url: './data/showData.php',
data: {
timeDif: timeDif,
nowTime: nowTime,
barrageId: currentId
},
success: function (backData) {
var spanArr = JSON.parse(backData)['list'];
currentId = JSON.parse(backData)['lastId'];
var rightSize = $('.swiper-container').width();
var heightSize = $('.swiper-container').height();
var dom = [];
for (var i = 0; i < spanArr.length; i++) {
var topVal = spanArr[i].topPer * heightSize;
dom[i] = document.createElement('span');
$('.barrageShow').append(dom[i]);
$(dom[i]).html(spanArr[i].value).css({
color: spanArr[i].color,
fontSize: spanArr[i].fontSize + "px",
top: topVal + "px",
right: -rightSize + "px"
})
.animate({
right: rightSize + "px"
}, 10000);
}
}
});
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
<--对应的showData.php-->
include './sql_login.php';
$now = $_GET['nowTime'];
$timeDif = $_GET['timeDif'];
$barrageId = $_GET['barrageId'];
$sql="select * from barrage where Id > '$barrageId'";
$result = mysql_query($sql);
$list = array();
$lastId = $barrageId;
while($row = mysql_fetch_array($result)){
$lastId = $row['Id'];
if($now - $timeDif + $row['timeDif'] - $row['timetemp'] > 10000)continue;
$item = array(
'barrageId' => $row['Id'],
'value' => $row['value'],
'timetemp' => $row['timetemp'],
'timeDif' => $row['timeDif'],
'color' => $row['color'],
'fontSize' => $row['fontSize'],
'topPer' => $row['topPer'],
'speed' => $row['speed'],
'wSize' => $row['wSize'],
'hSize' => $row['hSize']
);
array_push($list,$item);
}
echo json_encode(
array(
'lastId'=> $lastId,
'list'=>$list
)
);
mysql_close($con);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
总结
关键点(得到的经验):
1. 时间戳概念
要实现同步,必须找寻每个客户端的共同点作为参数对比,时间戳就是一个物理参数;
刚开始以为客户端的时间将是同步的,但是忽略的他们之前是存在的误差(人为修改时间或本身误差),所以必须获取到这样的误差值,用来计算和服务器同步即可.
2.运动的表象
jQuery中的animate其实也是让元素一帧一帧的移动;
第一版,让每一个弹幕以个人来运动,以span弹幕为参照物,每次刷新的实为span弹幕; 第二版则以弹屏为参照物,给弹屏里的每一个span弹幕设置定位,刷新弹屏,同时改变span弹幕的定位位置(同时也以时间戳为参考了);第三版,在页面加载时(或者刷新),获取此刻弹屏上出现有span弹幕位置,让其从各自位置开始以自身为参考运动,然后不断异步获取后台数据,如有符合条件的span被获取,则让其从弹屏最右侧位置开始以自身为参考运动.
3.前后台交互
在开发过程中,出现了span弹幕重复打印并运行的情况,检查前台逻辑没有问题,再检查后台php逻辑也没有问题,最后在浏览器控制台中检测到是以为数据请求及响应的时间过长,而js逻辑中刷新的频率较短,所以造成了重复打印多条.
原因: setInterval(add, 100);而下面的TTFB时长1.06s
解决过程:
-
往上一版进行测试,发现并没有造成TTFB过长,说明ajax异步时长不是影响,并且前台js逻辑也没有影响
-
那可能出在数据库上面,最后发现php连接数据库的时候使用了localhost,这样会进行DNS解析,会耗时,最后改为127.0.01果然解决了这个问题
需改进之处:
已实现多屏同步弹屏,并且压力测试较为良好.但是,
页面在不断进行setInterval操作,对浏览器消耗较大,需要进行缓存机制的处理;
前、后台数据的交互太过频繁,需要优化数据交互逻辑;
如真实放在互联网上运行,同步机制需要更加灵活,需加入负载均衡机制;
待项目成熟应进行弹幕框架封装;
… …
前端的坑还会继续一个个地去踩;
在路上, 会一个一个把坑尽量看清楚些, 看透彻了,
为了下一次快掉进去之前, 不抽自己嘴巴子, 而是昂首跨过去,
“来哇,互相伤害哇”!