微信小程序自定义计时器功能

手机APP/开发
518
0
0
2023-02-12

最近想在在做的微信小程序加一个计时器功能,就是可以设置一个时间,可以开始倒计时,暂停,最终实现结果(图1,2所示),可能这个配色及样式有点糟糕毕竟css太难了 ,可以在这个基础上进行扩展,如果时间到了会弹出图片或者播放音乐等等

图1

图2

1. block.wxml编写,写出计时器大概骨架

wxml中编写出大体需要的组件,代码如下:

<!--index.wxml-->
<image class="bg" src="../../images/webp (2).webp"></image>
<view hidden="{{clockShow}}">
  <view class="slider">
      <slider min="1" max="60" show-value activeColor="#E7624F"
      backgroundColor="#666666" value="{{time}}" bindchange="slideChange"></slider>
      </view>
      <view class="task_text">
        <view class="task_title">选择一个任务</view>
        <view class="task_desc">在接下来的{{time}}分钟内,您将专注做这件事</view>
      </view>
      <view class="task_cate">
        <view wx:for="{{cateArr}}" class="cate_item" wx:key="cate" bindtap="clickCate"
        data-index="{{index}}">
          <view class="cate_icon"> <image src="../../images/{{item.icon}}.png"></image> </view>
          <view class='cate_text {{index == cateActive ? "cate_text_active" : ""}}'>{{item.text}}</view>
        </view>
        <view class="start" bindtap="start">
        开始专注
        </view>
  </view>
</view>

<view class="clock" hidden="{{!clockShow}}" style="height:{{clockHeight}}rpx">
  <view class="progress">
    <canvas canvas-id="progress_bg" class="progress_bg"></canvas>
    <canvas canvas-id="progress_active" class="progress_active"></canvas>
    <view class="progress_text">{{timeStr}}</view>
  </view>
  <view class="btns">
    <view class="okBtn" bindtap="ok" wx:if="{{okShow}}">返回</view>
    <view class="pauseBtn" bindtap="pause" wx:if="{{pauseShow}}">暂停</view>
    <view class="continueCancelBtn" wx:if="{{continueCancelShow}}">
      <view class="continueBtn" bindtap="continue">继续</view>
      <view class="cancelBtn" bindtap="cancel">放弃</view>
    </view>
  </view>
</view>

2. block.wxss编写,写出计时器大概骨架

block.wxss对wxml中的组件编写样式,实现好看背景及布局,代码如下:

.adv1{
  width: 100%;
  height: 900rpx;
  background: url('/img/ba3.png') no-repaeat 0 0;
  background-size: contain;
}
.adv-img{
  width: 100%;
  height: 900rpx;
  position: absolute;
}
.tiaoguo{
  font-size: 25rpx;
  background-color: wheat;
  border-radius: 80rpx;
  display: inline-block;
  margin-left: 10rpx;
  position: absolute;
  z-index: 999;
  right: 25rpx;
  top: 850rpx;
  padding-left: 10rpx;
  padding-right: 10rpx;
}
button{
    border-radius: 18rpx;
    width: 220rpx;
    background-color: #EECBAD;
    color: #8B5742;
    margin-top: 38rpx;
    font-size: 33rpx;
}
.text2{
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    margin-top: 23rpx;
    font-size: 28rpx;
}

.bg{
  width: 100%;
  height: 100%;
  position:fixed; 
  background-size:100% 100%;
  z-index: -1;
  filter: blur(10rpx);
}
.silder{
  width: 650rpx;
  margin: 40rpx auto;
}
.task_text{
  height: 120rpx;
  margin: 40rpx auto;
  text-align: center;
}
.task_text .task_title{
  font-size: 35rpx;
  height: 70rpx;
  line-height: 70rpx;
}
.task_text .task_desc{
  font-size: 30rpx;
  height: 50rpx;
  line-height: 50rpx;
  color: #999999;
}
.task_cate{
  width: 660rpx;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
}
.task_cate .cate_item{
  width: 220rpx;
  height: 130rpx;
  text-align: center;
  margin-bottom: 50rpx;
}
.task_cate .cate_item .cate_icon{
  height: 70rpx;
}
.task_cate .cate_item .cate_icon image{
  width: 50rpx;
  height: 50rpx;
}
.task_cate .cate_item .cate_text{
  height: 60rpx;
  line-height: 60rpx;
  font-size: 30rpx;
}
.task_cate .cate_item .cate_text_active{
  color: #e41749;
}
.start{
  width: 280rpx;
  height: 90rpx;
  line-height: 90rpx;
  text-align: center;
  margin: 40rpx auto;
  border: 2rpx solid #e41749;
  color: #e41749;
  border-radius: 20rpx;
}
.clock{
  overflow: hidden;
  background: #8ac6d1;
}
.progress{
  width: 400rpx;
  height: 400rpx;
  /* background: orange; */
  margin: 140rpx auto;
  position: relative;
}
.progress .progress_bg,.progress_active{
  position: absolute;
  left: 0;
  top: 0;
  width: 400rpx;
  height: 400rpx;
}
.progress .progress_text{
  width: 160rpx;
  height: 60rpx;
  line-height: 60rpx;
  font-size: 30rpx;
  color: #ffffff;
  text-align: center;
  position: absolute;
  left: 120rpx;
  top: 170rpx;
}
.btns .okBtn, .btns .pauseBtn, .btns .continueBtn, .btns .cancelBtn{
  width: 280rpx;
  height: 80rpx;
  line-height: 80rpx;
  text-align: center;
  color: #ffffff;
  border: 3rpx solid #ffffff;
  border-radius: 20rpx;
  margin: 0 auto 20rpx auto;
}

3. block.js编写,写出计时器大概骨架

block.js动态绑定数据,实现开始计时,以及暂停计时等功能,代码如下:

//获取util实例
const app = getApp()
const util = require('../../utils/util.js')

Page({
  data: {
    clockShow:false,
    clockHeight:0,
    time:'5',
    mTime:300000,
    timeStr:'05:00',
    rate:'',
    timer:null,
    cateArr:[
      {
        icon: 'work',
        text: '工作'
      },
      {
        icon: 'study',
        text: '学习'
      },
      {
        icon: 'think',
        text: '思考'
      },
      {
        icon: 'write',
        text: '写作'
      },
      {
        icon: 'sport',
        text: '运动'
      },
      {
        icon: 'read',
        text: '阅读'
      }
    ],
    cateActive:'0',
    okShow:false,
    pauseShow:true,
    continueCancelShow:false
  },

  onLoad: function() {
    var res = wx.getSystemInfoSync();
    var rate = 750 / res.windowWidth;
    console.log(rate);
    this.setData({
      rate:rate,
      clockHeight:rate * res.windowHeight
    })
    
  },


  
  slideChange:function(e){
    this.setData({
      time:e.detail.value
    })
  },
  clickCate:function(e){
    this.setData({
      cateActive:e.currentTarget.dataset.index
    })
  },
  start:function(){
    this.setData({
      clockShow:true,
      mTime:this.data.time*60*1000,
      timeStr:parseInt(this.data.time) >= 10 ? this.data.time+':00' : 
      '0' + this.data.time+':00'
    })
    this.drawBg();
    this.drawActivve();
  },
  drawBg:function(){
    var lineWidth = 6 / this.data.rate;//px
    var ctx = wx.createCanvasContext('progress_bg');
    ctx.setLineWidth(lineWidth);
    ctx.setStrokeStyle('#000000');
    ctx.setLineCap('round');
    ctx.beginPath();
    ctx.arc(400/this.data.rate/2,400/this.data.rate/2,400/this.data.rate/2-2*lineWidth,0,2*Math.PI,false);
    ctx.stroke();
    ctx.draw();
  },
  // 动态画圆
  drawActivve:function(){
    var _this = this;
    var timer = setInterval(function(){
      //1.5-3.5
      var angle = 1.5 + 2*(_this.data.time*60*1000 - _this.data.mTime)/
      (_this.data.time*60*1000);
      var currentTime = _this.data.mTime - 100;
      _this.setData({
        mTime:currentTime
      });
      if(angle < 3.5){
        if(currentTime % 1000 == 0){
          var timeStr1 = currentTime / 1000;// s
          var timeStr2 = parseInt(timeStr1 / 60);// m
          var timeStr3 = (timeStr1 - timeStr2*60) >= 10 ? (timeStr1 - timeStr2*60) :
          '0'+(timeStr1 - timeStr2*60);
          var timeStr2 = timeStr2 >= 10 ? timeStr2 : '0'+timeStr2;
          _this.setData({
            timeStr:timeStr2+':'+timeStr3
          })
        }
        var lineWidth = 6 / _this.data.rate;//px
        var ctx = wx.createCanvasContext('progress_active');
        ctx.setLineWidth(lineWidth);
        ctx.setStrokeStyle('#ffffff');
        ctx.setLineCap('round');
        ctx.beginPath();
        ctx.arc(400/_this.data.rate/2,400/_this.data.rate/2,400/_this.data.rate/2-2*lineWidth,
          1.5*Math.PI,angle*Math.PI,false);
        ctx.stroke();
        ctx.draw();
      }else{
        var logs = wx.getStorageSync('logs') || [];
        logs.unshift({
          date:util.formatTime(new Date),
          cate:_this.data.cateActive,
          time:_this.data.time
        });
        wx.setStorageSync('logs', logs);
        _this.setData({
          timeStr:'00:00',
          okShow:true,
          pauseShow:false,
          continueCancelShow:false
        });
        clearInterval(timer);
      }
    },100)
    _this.setData({
      timer:timer
    })
  },
  pause:function(){
    clearInterval(this.data.timer);
    this.setData({
      pauseShow:false,
      continueCancelShow:true,
      okShow:false
    })
  },
  continue:function(){
    this.drawActivve();
    this.setData({
      pauseShow:true,
      continueCancelShow:false,
      okShow:false
    })
  },
  cancel:function(){
    clearInterval(this.data.timer);
    this.setData({
      pauseShow:true,
      continueCancelShow:false,
      okShow:false,
      clockShow:false
    })
  },
  ok:function(){
    clearInterval(this.data.timer);
    this.setData({
      pauseShow:true,
      continueCancelShow:false,
      okShow:false,
      clockShow:false
    })
  }


})

4. 在微信小程序项目根目录下新建utils文件夹,放置utils.js的文件

utils文件夹一定在项目根目录下(图3所示),utils.js文件是对日期格式进行处理,代码如下:

图3

utils.js代码:

const formatTime = date => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()

  return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}

const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}

module.exports = {
  formatTime: formatTime
}

到这里,我们就可以实现微信小程序简单的计时器,你也可以在这个基础上实现一些更复杂的更好看的功能。