最近想在在做的微信小程序加一个计时器功能,就是可以设置一个时间,可以开始倒计时,暂停,最终实现结果(图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 | |
} |
到这里,我们就可以实现微信小程序简单的计时器,你也可以在这个基础上实现一些更复杂的更好看的功能。