微信小程序setTimeout实现无限循环倒计时

适用场景:

循环播放视频, 广告,等

我这里用一个签到送积分场景广告视频来实现该效果:

我们先来看一下效果:

wxml

<!--pages/daily-attendance/index.wxml-->
<view class="daily-attendance-top">
	<image class="daily-attendance-img" src="http://ico.dongtiyan.com/tu-23.png"></image>
	<view class="daily-attendance-desc">
		<text>您已经累计签到</text>
		<text> {{count}} </text>
		<text>天, </text>
		<text>获得</text>
		<text> {{getCount}} </text>
		<text>星球算力</text>
	</view>
</view>


<view class="daily-attendance-con">
	<!-- 日历 S -->
	<view class="calendar">
		<view class="daily-attendance-con-top">
			<image src="http://ico.dongtiyan.com/tu-25.png" bindtap="handleCalendar" data-handle="prev"></image>
			<view>{{cur_year || '--'}}年{{cur_month || '--'}}月</view>
			<image src="http://ico.dongtiyan.com/tu-24.png" bindtap="handleCalendar" data-handle="next"></image>
		</view>
		<view class="period">
			<block wx:for="{{weeks_ch}}" wx:for-idx="{{index}}" wx:key="index">
				<view>{{item}}</view>
			</block>
		</view>
		<view class="days">
			<!-- 列 -->
			<view class="culumns" wx:for="{{days.length/7}}" wx:for-index="i" wx:key="i">
				<view wx:for="{{days}}" wx:for-index='j' wx:key="j">
					<!-- 行 -->
					<view class="rows" wx:if="{{j/7 == i}}">
						<view class="rows" wx:for="{{7}}" wx:for-index="k" wx:key="k">
							<!-- 每个月份的空的单元格 -->
							<view class="cell" wx:if="{{days[j+k].date == null}}">
								<text decode="{{true}}">&nbsp;&nbsp;</text>
							</view>
							<!-- 每个月份有数字的单元格 -->
							<view class="cell" wx:else>
								<!-- 当前日期已签到 -->
								<view wx:if="{{days[j+k].isSign == true}}" style="background-color: #FFB21E" class="cell">
									<block wx:if="{{days[j+k].date == current_date}}">
										<text>今</text>
									</block>
									<block wx:else>
										<text>{{days[j+k].date}}</text>
									</block>
								</view>
								<!-- 当前日期未签到 -->
								<view wx:else>
									<block wx:if="{{days[j+k].date == current_date}}">
										<text>今</text>
									</block>
									<block wx:else>
										<text>{{days[j+k].date}}</text>
									</block>
								</view>
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
	<!-- 日历 E -->
	<!-- 签到描述 S -->
	<view class="sign-in-desc">每次成功签到赠送1体星球算力</view>
	<!-- 签到描述 E -->
	<!-- 签到按钮 S -->
	<view class="sign-in-btn">
		<block wx:if="{{defaults != 1}}">
      <view class="sign-in" bindtap="chooseSignIn">签到</view>
    </block>
    <block wx:else>
      <view class="sign-in">已签到</view>
    </block>
	</view>
	<!-- 签到按钮 E -->
	<!-- 签到规则 S -->
	<view class="sign-in-rules">
		<view>签到规则</view>
		<view>1、每日签到可领取1星球算力;</view>
		<view>2、签到打卡积分规则</view>
		<view>①每日签到增加1分,当日重复签到不会重复计数</view>
		<view>②连续签到7天会有额外算力,如:第7天,总积分为7分,额外增加3分,其余连续签到天数均无额外积分;</view>
		<view>3、签到打卡奖励兑换规则</view>
		<view>①签到打卡奖励兑换方法 在懂体验线上积分商城选择相应商品进行兑换购买,兑换成功后我们会在三个工作日邮递寄出。</view>
	</view>
	<!-- 签到规则 E -->
	<!-- 装饰 S -->
	<image class="decorate" src="http://ico.dongtiyan.com/tu-27.png"></image>
	<!-- 装饰 E -->
</view>

<!-- 签到视频 S -->
<view class="mask-layer" hidden="{{signInDefaults}}"></view>
<view class="sign-in-video" hidden="{{signInDefaults}}">
	<view class="total-time">{{currentTime}}</view>
	<video class="video" id="video" src="{{video}}" autoplay="{{signInDefaults === false? true: false}}" controls="{{controls}}" loop="{{loop}}"></video>
	<block wx:if="{{countDownNum != 0}}">
		<view class="get-btn">{{countDownNum}} 秒后可领取</view>
	</block>
	<block wx:else>
		<view class="get-btn" bindtap="chooseImmediatelyReceive">立即领取</view>
	</block>
</view>

<!-- 签到成功 S -->
<view class="mask-layer" hidden="{{succeedDefaults}}"></view>
<view class="sign-in-succeed" hidden="{{succeedDefaults}}">
	<view class="succeed-img">{{signInSuccessfully}}</view>
	<view class="succeed-desc">
		<text>每日签到可获得</text>
		<text> 1 </text>
		<text>星球算力</text>
	</view>
	<view class="confirm-btn" bindtap="chooseConfirm">确定</view>
</view>
<!-- 签到成功 E -->

wxss

.daily-attendance-top {
  background: linear-gradient(#feb305, #fe850f);
  text-align: center;
}
.daily-attendance-img {
  height: 62rpx;
  width: 275rpx;
  margin-top: 40rpx; 
}
.daily-attendance-desc {
  font-size: 28rpx;
  color: #A04B0C;
  height: 108rpx;
  background: linear-gradient(#FFAF4A, #FFD156);
  border-radius: 20rpx;
  margin: 59rpx 30rpx 0;
  padding-top: 35rpx;
}
.daily-attendance-desc text:nth-child(2), .daily-attendance-desc text:nth-child(5) {
  color: #F73A3F;
}
/* 打卡日历 */
.daily-attendance-con {
  width: 100%;
  background: #FDE28D;
  position: absolute;
}
.calendar {
  width: 92%;
  background: #FFFFFF;
  border-radius: 20rpx;
  margin: -37rpx 30rpx 0;
  position: relative;
  z-index: 99;
}
.daily-attendance-con-top {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 38rpx 24rpx 51rpx;
}

.daily-attendance-con-top image {
  width: 9rpx;
  height: 17rpx;
}

.daily-attendance-con-top view {
  margin:  0 57rpx;
  font-size: 24rpx;
  color: #A04B0C;
}

.period {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  padding: 0 40rpx 20rpx;
  font-size: 24rpx;
  color: #E1A172;
}
.days {
  padding: 27rpx 27rpx 0;
  border-radius: 20rpx;
  color: #A04B0C;
  font-size: 24rpx;
}
.culumns {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.culumns .rows {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-bottom: 27rpx;
}

.culumns .rows .cell {
  width: 48rpx;
  height: 48rpx;
  text-align: center;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* 签到描述 */
.sign-in-desc {
  font-size: 24rpx;
  color: #A04B0C;
  padding-top: 26rpx;
  text-align: center;
}
.sign-in {
  background-image: url("http://ico.dongtiyan.com/tu-26.png");
  background-size: cover;
  width: 549rpx;
  height: 109rpx;
  text-align: center;
  line-height: 95rpx;
  margin: 69rpx auto 63rpx;
  font-size: 32rpx;
  color: #FFFFFF;
}

/* 签到规则 */
.sign-in-rules {
  background: #F7D66F;
  margin: 0 30rpx 0;
  border-radius: 20rpx;
  padding: 40rpx;
  font-size: 24rpx;
  color: #A04B0C;
}
.sign-in-rules view:nth-child(1) {
  margin-bottom: 30rpx;
}
.sign-in-rules view:nth-child(2) {
  margin-bottom: 26rpx;
}
.sign-in-rules view:nth-child(4) {
  margin-left: 38rpx;
}
.sign-in-rules view:nth-child(5) {
  margin-left: 38rpx;
  margin-bottom: 26rpx;
}

.sign-in-rules view:nth-child(7) {
  margin-left: 38rpx;
}
.decorate {
  width: 100%;
  height: 139rpx;
}
/* 签到视频 */
.sign-in-video {
  position: fixed;
  z-index: 999;
  left: 142rpx;
  bottom: 328rpx;
}
.video {
  width: 467rpx;
  height: 518rpx;
  border-radius: 20rpx;
}
video::-webkit-media-controls-timeline {
  display: none;
}
.get-btn {
  margin: 36rpx 32rpx 0;
  background-image: url("http://ico.dongtiyan.com/tu-26.png");
  background-size: 100% 100%;
  height: 91rpx;
  text-align: center;
  line-height: 85rpx;
  color: #FFFFFF;
  font-size: 32rpx;
}
.total-time {
  position: absolute;
  z-index: 999;
  color: #FFFFFF;
  font-size: 20rpx;
  width: 40rpx;
  height: 40rpx;
  line-height: 40rpx;
  text-align: center;
  border-radius: 50%;
  background: #000000;
  opacity: 0.5;
  right: 25rpx;
  top: 26rpx;
}

/* 签到成功 */
.sign-in-succeed {
  width: 467rpx;
  height: 518rpx;
  position: fixed;
  z-index: 999;
  left: 142rpx;
  bottom: 328rpx;
  border: 4rpx solid #FAC663;
  background: #FFFFFF;
  border-radius: 20rpx;
  justify-content: center;
}
.succeed-img {
  background-image: url('http://ico.dongtiyan.com/tu-28.png');
  background-size: cover;
  width: 322rpx;
  height: 95rpx;
  color: #FFFFFF;
  font-size: 28rpx;
  text-align: center;
  margin: 47rpx auto 0;
  line-height: 60rpx;
}
/* 签到描述 */
.succeed-desc {
  font-size: 24rpx;
  color: #000000;
  text-align: center;
  margin: 101rpx 0 126rpx;
}
.succeed-desc text:nth-child(2) {
  color: #F73A3F;
}
/* 确定 */
.confirm-btn {
  background-image: url('http://ico.dongtiyan.com/tu-26.png');
  background-size: 100% 100%;
  width: 311rpx;
  height: 91rpx;
  color: #FFFFFF;
  text-align: center;
  font-size: 32rpx;
  line-height: 80rpx;
  margin:  0 auto;
}

js

// pages/daily-attendance/index.js
const app = getApp()
const format = require('../../utils/util.js');
//打卡日历页面
var util = require('../../utils/util.js');
var timers
Page({

  /**
   * 页面的初始数据
   */
  data: {

    objectId: '',
    cur_year: 0, // 年
    cur_month: 0, // 月
    current_date: 0, // 当前日
    weeks_ch: [], // 周期
    count: 0, // 签到天数
    signInSuccessfully: "",                 // 签到状态
    getCount: 0, // 获得星球算力
    days: [], // 月日期列表
    signUp: [{
      date: '2020/6/21',
      isSign: false,
    }, {
      date: '2020/6/20',
      isSign: false,
    }], //
    video: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4", // 广告视频
    autoplay: false, // 自动播放
    controls: false, // 隐藏控件
    loop: true, // 是否循环
    timers: "", // 视频定时器
    currentTime: 5, // 视频播放总时长
    currentTimes: '',
    timer: '', // 定时器
    countDownNum: 5, // 倒计时初始值
    signInDefaults: true, // 签到默认
    succeedDefaults: true, // 成功默认
    defaults: 0, // 默认按钮 
  },
  /**
   * 获取签到状态
   */
  getsignInState: function () {
    var _this = this;
    wx.request({
      url: app.globalData.apiUrl + 'api/user/user/sign_log',
      data: {
        token: wx.getStorageSync('token')
      },
      method: "POST",
      header: app.globalData.header,
      success: function (res) {
        console.log(res)
        _this.setData({
          signUp: res.data.data,
          defaults: res.data.status
        })
        _this.onJudgeSign()
      },
      fail: function (err) {
        wx.showToast({
          title: '请求超时, 请稍后再试~',
          icon: 'none'
        })
      }
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.setData({
      objectId: 1
    })
    /**
     * 获取当前年月
     */
    const date = new Date();
    const cur_year = date.getFullYear();
    const cur_month = date.getMonth() + 1;
    const weeks_ch = ['日', '一', '二', '三', '四', '五', '六'];
    this.calculateEmptyGrids(cur_year, cur_month);
    this.calculateDays(cur_year, cur_month);
    const current_date = date.getDate() < 10 ? '0' + date.getDate() : date.getDate(); //获取当前日
    /**
     * 获取当前用户当前任务的签到状态
     */
    this.getsignInState()
    this.setData({
      cur_year: cur_year,
      cur_month: cur_month,
      weeks_ch: weeks_ch,
      current_date: current_date
    })
  },
  /**
   * 获取当月共多少天
   */
  getThisMonthDays: function (year, month) {
    return new Date(year, month, 0).getDate()
  },
  /**
   * 获取当月第一天星期几
   */
  getFirstDayOfWeek: function (year, month) {
    return new Date(Date.UTC(year, month - 1, 1)).getDay();
  },
  /**
   * 计算当月1号前空了几个格子, 把它填充在days数组的前面
   */
  calculateEmptyGrids: function (year, month) {
    var that = this;
    /**
     * 计算每个月时要清零
     */
    that.setData({
      days: []
    });
    const firstDayOfWeek = this.getFirstDayOfWeek(year, month);
    if (firstDayOfWeek > 0) {
      for (let i = 0; i < firstDayOfWeek; i++) {
        var obj = {
          date: null,
          isSign: false
        }
        that.data.days.push(obj);
      }
      this.setData({
        days: that.data.days
      });
      /**
       * 清空
       */
    } else {
      this.setData({
        days: []
      });
    }
  },
  /**
   * 回执当月天数占的格子, 并把它放到days数组中
   */
  calculateDays: function (year, month) {
    var that = this;
    const thisMonthDays = this.getThisMonthDays(year, month);
    for (let i = 1; i <= thisMonthDays; i++) {
      var obj = {
        date: i,
        isSign: false
      }
      that.data.days.push(obj);

    }
    this.setData({
      days: that.data.days
    });
  },
  /**
   * 切换控制年月,上一个月,下一个月
   */
  handleCalendar: function (e) {
    const handle = e.currentTarget.dataset.handle;
    const cur_year = this.data.cur_year;
    const cur_month = this.data.cur_month;
    if (handle === 'prev') {
      let newMonth = cur_month - 1;
      let newYear = cur_year;
      if (newMonth < 1) {
        newYear = cur_year - 1;
        newMonth = 12;
      }
      this.calculateEmptyGrids(newYear, newMonth);
      this.calculateDays(newYear, newMonth);
      this.getsignInState();
      this.setData({
        cur_year: newYear,
        cur_month: newMonth
      })
    } else {
      let newMonth = cur_month + 1;
      let newYear = cur_year;
      if (newMonth > 12) {
        newYear = cur_year + 1;
        newMonth = 1;
      }
      this.calculateEmptyGrids(newYear, newMonth);
      this.calculateDays(newYear, newMonth);
      this.getsignInState();
      this.setData({
        cur_year: newYear,
        cur_month: newMonth
      })
    }
  },
  // 匹配判断当月与当月哪些日子签到打卡
  onJudgeSign: function () {
    var _this = this;
    var signs = _this.data.signUp;
    var daysArr = _this.data.days;
    for (var i = 0; i < signs.length; i++) {
      var time = format.formatTime(signs[i].add_time, 'Y-M-D')
      var current = new Date(time.replace(/-/g, "/"));
      var year = current.getFullYear(); // 年
      var month = current.getMonth() + 1; // 月
      var day = current.getDate(); //日
      day = parseInt(day);
      for (var j = 0; j < daysArr.length; j++) {
        if (year == _this.data.cur_year && month == _this.data.cur_month && daysArr[j].date == day && daysArr[j].isSign == false) {
          daysArr[j].isSign = true;
          var count = this.data.count + 1
          var getCount = this.data.getCount + 1
        }
      }
      _this.setData({
        days: daysArr,
        count: count,
        getCount: getCount,
      })
      // console.log(this.data.days)
    }
  },
  /**
   * 签到
   */
  chooseSignIn: function () {
    this.setData({
      signInDefaults: !this.data.signInDefaults,
    })
    this.countDown()
    this.videoPlay()
  },
  /**
   * 立即领取
   */
  chooseImmediatelyReceive: function () {
    var _this = this;
    if (!wx.getStorageSync('token')) {
      wx.showModal({
        title: '提示',
        content: '请先授权登录',
        cancelColor: 'cancelColor',
        success: function (res) {
          if (res.confirm) {
            wx.navigateTo({
              url: '../my/my-login/index',
            })
          }
        }
      })
    } else {
      wx.request({
        url: app.globalData.apiUrl + 'api/user/user/user_sign',
        data: {
          token: wx.getStorageSync('token')
        },
        method: "POST",
        header: app.globalData.header,
        success: function (res) {
          _this.setData({
            signInSuccessfully: res.data.msg
          })
        },
        fail: function (err) {
          wx.showToast({
            title: "请求超时, 请稍后再试~",
            icon: 'none'
          })
        }
      })
      this.setData({
        signInDefaults: !this.data.signInDefaults,
        succeedDefaults: !this.data.succeedDefaults
      })
      this.videoStop()
      clearInterval(this.data.timers)
    }
  },
  /**
   * 领取确认
   */
  chooseConfirm: function () {
    var _this = this;
    this.setData({
      succeedDefaults: !this.data.succeedDefaults,
      defaults: !this.data.defaults
    })
    this.onJudgeSign()
  },
  /**
   * 倒计时
   */
  countDown: function () {
    var _this = this;
    var countDownNum = _this.data.countDownNum; // 获取倒计时初始值
    // 如果将定时器设置在外面,那么用户就看不到countDownNum的数值动态变化,所以要把定时器存进data里面
    _this.setData({
      timer: setInterval(function () { // 这里把setInterval赋值给变量名为timer的变量
        //每隔一秒countDownNum就减一, 实现同步
        countDownNum--;
        // 然后把countDownNum存进data, 好让用户时间在倒计时
        _this.setData({
          countDownNum: countDownNum
        })
        if (countDownNum == 0) {
          // 这里特别要注意,计时器是始终一直在走的,如果你的时间为0, 那么就要关掉定时器,不然相当好性能
          // 因为timer是存在data里面的, 所以在关掉是,也要在data里取出后再关闭
          clearInterval(_this.data.timer)
        }
      }, 1000)
    })
  },
  /**
   * 视频播放
   */
  videoPlay: function () {
    var videoplay = wx.createVideoContext('video')
    videoplay.play()
    this.videoCountDown()
  },
  /**
   * 视频关闭
   */
  videoStop: function () {
    var videostop = wx.createVideoContext('video')
    videostop.stop()
  },

  /**
   * 视频倒计时
   */
  videoCountDown: function () {
    var _this = this;
    var currentTime = this.data.currentTime;
    timers = setTimeout(function () { // 这里把setInterval赋值给变量名为timer的变量
      // 每隔一秒countDownNum就减一, 实现同步
      currentTime--;
      // 然后把countDownNum存进data, 好让用户时间在倒计时
      _this.setData({
        currentTime: currentTime
      })
      if(currentTime == -1) {
       _this.setData({
         currentTime: 5
       })
      }
      this.videoCountDown()
    }.bind(this), 1000, _this)
  },
  
})

以上就是所有代码,有什么更好的实现方式请下面留言,互相交流,谢谢

 

如果对你有帮助,请关注一下博主的小程序支持一下, 在此谢谢了

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值