js定时红包雨

1,请准备一个模版,像下面这样

<div class="content">
  <div class="hide">
    <div class="red-box" data-txt>
      <img src="hongbao.png">
    </div>
  </div>
</div>

.content{position: relative;}
.red-box{position: absolute;}
.red-box img{width:50px; height:auto; cursor: pointer;}
.hide{display: none;}

2,请引入我这里是用jquery制作的,节点操作大同小异

<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>

3,我们先做来模拟一下后台返回的数据组织方式吧

// 原始数据  
let source = JSON.parse('[{"itemid":"3","lid":"9","fromtime":"1656572514","endtime":"1656579714","nums":"10","prize":"\u906e\u9633\u4f1e","thumb":"","probability":"100","wnums":"0"}]')

// 包装一下
var sourceArr = []
source.forEach(function(v){
    let tmpObj = {
       ft: v.fromtime * 1000, // 开始时间
       et: v.endtime * 1000, // 结束时间 结束时间就是需要控制红包雨要下多久的参数呢
       lid: v.lid // 活动id 这个id就是我们需要触发的抽奖活动的信息
    }
    sourceArr.push(tmpObj)
})

4,因为活动不是每天都有,我们必须有手段去判断今天的日期和活动的日期是否是匹配,非活动日期不做操作,具体请看下图

// 给Date类添加了一个新的实例方法format
// 首先是需要格式化日期
  Date.prototype.format = function(fmt) {
    let o = {
      'M+': this.getMonth() + 1, // 月份
      'd+': this.getDate(), // 日
      'h+': this.getHours(), // 小时
      'm+': this.getMinutes(), // 分
      's+': this.getSeconds(), // 秒
      'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
      S: this.getMilliseconds() // 毫秒
    }
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(
              RegExp.$1,
              (this.getFullYear() + '').substr(4 - RegExp.$1.length)
      )
    }
    for (let k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(
                RegExp.$1,
                RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
        )
      }
    }
    return fmt
  }

// 获取当天和活动日期的时间戳
let now = new Date().getTime()
let nowDate = new Date((new Date(now)).format('yyyy-MM-dd')).getTime() // 格式化为 2022-06-25 获取截止到 日 的时间戳

// 把活动时间单独放到一个taskDate数组,因为活动日期属于前置判断
// ft 为活动开始时间
taskDate.push(
    new Date((new Date(v.ft)).format('yyyy-MM-dd')).getTime()
)

// 最后进行当日与活动日的判断即可
Array.from(new Set(taskDate)).includes(nowDate)

至此,关于某天需要执行活动的代码片段结束

5, 下面我们来说一下怎么来执行这个红包雨吧

// 启动多个定时任务 
execTimeArr.forEach(function(execV) {
  // 计算当前时间是否包含在开始-结束
  if (now > execV.ft && now < execV.et) {
    execTime = 0 // 立即执行
    persistTime = execV.et - now // 已经开始执行那继续执行剩余时间
  } else {
    execTime = execV - now // 等待
    persistTime = execV.et - execV.ft // 未开始则执行 结束 减去 开始的时间
  }
let timer = setTimeout(function() {
  task(persistTime, execV.lid) // 任务实体 传入需要执行的时间, 传入定时任务需要绑定的 抽奖活动id
  }, execTime)
  // 这是用来清理 TimeOut 的 队列
  timerList.push({
    time: execV, // 执行时间
    timer: timer // 定时任务
  })
})

// 好了,我们再来看下 task 如何工作吧
//启用定时器,循环创建红包雨
function task(persistTime, lid){
  // 这个就是结束时间减去开始时间,得到一个次数,可以控制红包雨需要下多久
  var count = parseInt(persistTime / 300); 
  timer = setInterval(function(){
    if(count === 0){
      clearInterval(timer);
    }else{
      count--
      $('.time').text(count+'s');
      createRedBox(lid); // 创建红包
    }
  }, 300);
}
//创建红包 lid 需要携带的红包id
function createRedBox(lid){
  var $newNode = $redBox.clone(true); // 克隆节点
  $newNode.attr('data-txt', Math.random()*100); // 分配文本
  // 增加红包id的属性
  $newNode.attr('data-lid', lid); // 这里是抽奖活动的id
  // 随机显示
  $newNode.css({
    'z-index':zIndex++,
    'left':getRandom(basePadding,maxLeftPX)+'px', // 其实这里换translate性能会好
    'transform': 'rotate('+getRandom(-30,30)+'deg)' // 随机旋转
  });
  // 追加节点
  $content.append($newNode);
  redBoxSpeed($newNode, 5);
}

//设置红包移动速度及销毁时间
function redBoxSpeed($el,time){
  // 执行动画
  $el.animate({top:'800px',},time*1000,function(){
    $el.remove(); // 结束后隐藏红包节点
  });
}

// 好了,到此为止,关于红包的怎么生成,生成多少,怎么运动我们都定义好了。包括预留到红包上的id或者各类文本。后面都会用到

6,最后,我们给我们的红包上绑定一个点击事件吧

<div class="dialog" id="dialog">
  <p class="title"></p>
</div>

// 这些资源都是可以按照你们自己的需求去做
<link rel="stylesheet" href="http://apps.bdimg.com/libs/jqueryui/1.10.4/css/jquery-ui.min.css">
<link rel="stylesheet" href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap.min.css">
<script src="http://apps.bdimg.com/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script src="http://apps.bdimg.com/libs/bootstrap/3.3.0/js/bootstrap.min.js"></script>

//将红包绑定事件
function bindEvent(){
  $content.on('click','.red-box',function(){
    let lid = $(this).data('lid')
    // 这里可以是各类的异步操作,然鹅我们的重点不是他,所以我就打个样
    // 此处弹窗要增加 ajax ,success 后弹出
    $("#dialog").dialog({
      autoOpen:false,
      modal:true,
      hide:{
        effect: "explode",
        duration: 1000
      }
    });
    $('.title').text('活动id为'+lid);
    $("#dialog").dialog('open');
  });
}

7,到此,从数据处理到动画制作再到数据提交,我们的逻辑片段已经完成,那么将他们串连起来

// 这里就不再加html和引入的资源

// 给Date类添加了一个新的实例方法format
  Date.prototype.format = function(fmt) {
    let o = {
      'M+': this.getMonth() + 1, // 月份
      'd+': this.getDate(), // 日
      'h+': this.getHours(), // 小时
      'm+': this.getMinutes(), // 分
      's+': this.getSeconds(), // 秒
      'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
      S: this.getMilliseconds() // 毫秒
    }
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(
              RegExp.$1,
              (this.getFullYear() + '').substr(4 - RegExp.$1.length)
      )
    }
    for (let k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(
                RegExp.$1,
                RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
        )
      }
    }
    return fmt
  }
  var sourceArr = []
  // 测试数据
  let source = JSON.parse('[{"itemid":"3","lid":"9","fromtime":"1656572514","endtime":"1656579714","nums":"10","prize":"\u906e\u9633\u4f1e","thumb":"","probability":"100","wnums":"0"}]')
  source.forEach(function(v){
      let tmpObj = {
        ft: v.fromtime * 1000,
        et: v.endtime * 1000,
        lid: v.lid
      }
      sourceArr.push(tmpObj)
  })
  let $content = $('.content');
  let $redBox = $('.red-box');
  let redContentWidth = $content.width();
  let redBoxWidth =$redBox.width();
  let basePadding =30 ;
  let maxLeftPX=redContentWidth-redBoxWidth-basePadding*2;
  let config = {
    time: sourceArr // 每天执行时间段
  };
  let now = new Date().getTime()
  let nowDate = new Date((new Date(now)).format('yyyy-MM-dd')).getTime() // 格式化为 2022-06-25 获取截止到 日 的时间戳
  let execTimeArr = []
  // 取任务当日日期,组织数组
  let taskDate = [];
  config.time.forEach(function(v) {
    taskDate.push(
      new Date((new Date(v.ft)).format('yyyy-MM-dd')).getTime()
    )
    // 结束时间超过当前时间不计入不再执行
    if (v.et > now) {
      execTimeArr.push(v)
    }
  })

  // 执行总任务
  let timerList = [] // 定时器队列
  // Array.from(new Set(taskDate)).includes(nowDate) 判断当天日期是否包含在后台返回的接口日期中
  if (execTimeArr.length > 0 && Array.from(new Set(taskDate)).includes(nowDate)) {
    // 启动多个定时任务
    execTimeArr.forEach(function(execV) {
      // 计算当前时间是否包含在开始-结束
      if (now > execV.ft && now < execV.et) {
        execTime = 0 // 立即执行
        persistTime = execV.et - now // 已经开始执行那继续执行剩余时间
      } else {
        execTime = execV - now // 等待
        persistTime = execV.et - execV.ft // 未开始则执行 结束 减去 开始的时间
      }
      let timer = setTimeout(function() {
        task(persistTime, execV.lid) // 任务实体 传入需要执行的时间, 传入定时任务需要绑定的 抽奖活动id
      }, execTime)
      // 这是用来清理 TimeOut 的 队列
      // 当 task 中 count === 0 逻辑 成立,获取timerList中lid对应的那一项将TimeOut清理
      timerList.push({
        lid: execV.lid, // 活动id
        timer: timer // 定时任务
      })
    })
  }

  //启用定时器,循环创建红包雨
  function task(persistTime, lid){
    // count 由 总时间 / 300
    var count = parseInt(persistTime / 300);
    timer = setInterval(function(){
      if(count === 0){
        clearInterval(timer);
        // 清理 TimeOut
        if (timerList.length > 0) {
            timerList.forEach(function(l) {
              if (l.lid == lid) {
                  clearTimeout(l.timer)
              }
            })
        }
      }else{
        count--
        $('.time').text(count+'s');
        createRedBox(lid);
      }
    }, 300);
  }

  var zIndex= 1;
  var timer;

  function bindEvent(){
    //将红包绑定事件
    $content.on('click','.red-box',function(){
      let lid = $(this).data('lid')
      // 此处弹窗要增加 ajax ,success 后弹出
      $("#dialog").dialog({
        autoOpen:false,
        modal:true,
        hide:{
          effect: "explode",
          duration: 1000
        }
      });
      $('.title').text('活动id为'+lid);
      $("#dialog").dialog('open');
    });
  }

  //设置移动及旋转的距离,避免溢出屏幕
  function getRandom(min,max) {
    return Math.round(Math.random() * (max - min) + min);
  }

  //设置红包移动速度及销毁时间
  function redBoxSpeed($el,time){
    // 执行动画
    $el.animate(
      {
        top:'800px',
      },
      time*1000,
      function(){
        $el.remove(); // 结束后隐藏红包节点
      }
    );
  }

  //创建红包 lid 需要携带的红包id
  function createRedBox(lid){
    var $newNode = $redBox.clone(true); // 克隆节点
    $newNode.attr('data-txt', Math.random()*100); // 分配文本
    // 增加红包id的属性
    $newNode.attr('data-lid', lid);
    // 随机显示
    $newNode.css({
      'z-index':zIndex++,
      'left':getRandom(basePadding,maxLeftPX)+'px',
      'transform': 'rotate('+getRandom(-30,30)+'deg)'
    });
    // 追加节点
    $content.append($newNode);
    redBoxSpeed($newNode, 5);
  }

  bindEvent()

8,效果在这:https://v.youku.com/v_show/id_XNTg4MzE2NzkyMA==.html

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值