ajax实现无刷新弹幕效果

jQuery 简洁版

需求

  1. 输入框输入点击,生成随机样式的span
  2. 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();
              });
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

缺陷 
只能实现无刷新弹幕

改进思路 
数据分离出来: 
前台获取的数据, 先保存到后台; 
前台要显示, 再从后台调取.

JSON+Ajax版 实现简单同步

需求

  1. 输入框输入点击,生成随机样式的span
  2. span数据给后台将数据保存后
  3. 前台调取后台数据信息,完成span弹幕从右往左运动

实现

输入框输入点击,生成随机样式的span

//大同于第一版,其中添加
//topPer为出现的随机高度比例(代替之前的直接给值,因为不同屏幕高度不同)
//timeval为span弹幕创建时的时间戳(用于判断span的运动距离)
var timeVal = new Date().getTime();
var topPer = parseInt(Math.random() * heightSize) / heightSize;
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

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);}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
<--对应的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');
 ?>
 
 
  • 1
  • 2
  • 3
  • 4

缺陷 
能实现刷新数据不丢失 
但不能实现多屏同步效果

改进思路 
数据分离出来: 
之前保存在json文件中,改进为保存在MySQL数据库;

时间戳
这个概念非常重要,因为多屏同步, 每一个客户端的时间是不同的. 所以需要在加载网页的时候就要获取客户端的时间与服务器的时间来计算时间差; 
将每一个客户端的时间都转换为服务器的时间. 这样每一个客户端发出的请求就都是以服务器为标准, 看上去, 客户端发布一条span弹幕, 每一个打开页面的客户端都可以同步看见.

Mysql+Ajax版 实现简单同步

需求

  1. 输入框输入点击,生成随机样式的span
  2. span数据给后台将数据保存后
  3. 前台调取后台数据信息,完成span弹幕从右往左运动

实现

增加时间差概念

var cilentTime = new Date().getTime();
var timeDif;
$.ajax({
    url: './data/getCilentTime.php',
    data: {},
    success: function (backData) {
        timeDif = cilentTime - backData*1000;
    }
})
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
<--对应的getCilentTime.php-->
<?php 
   date_default_timezone_set("Asia/Shanghai");
   $now = time();
   echo $now;
 ?>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

输入框输入点击,生成随机样式的span

//大同于第二版
//添加时间差
 
 
  • 1
  • 2

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);}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
<--对应的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();
// $total = 0;
$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);
    // $total = $row['total'];
}

echo json_encode(
array(
    // 'total'=> intval($total),
    '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操作,对浏览器消耗较大,需要进行缓存机制的处理; 
前、后台数据的交互太过频繁,需要优化数据交互逻辑; 
如真实放在互联网上运行,同步机制需要更加灵活,需加入负载均衡机制; 
待项目成熟应进行弹幕框架封装; 
… …

前端的坑还会继续一个个地去踩; 
在路上, 会一个一个把坑尽量看清楚些, 看透彻了, 
为了下一次快掉进去之前, 不抽自己嘴巴子, 而是昂首跨过去, 
“来哇,互相伤害哇”!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心歌技术

打赏不能超过你的早餐钱!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值