本文最后更新于 693 天前,其中的信息可能已经有所发展或是发生改变。
最近做的一个小程序项目想做一个按钮 长按2s触发,并且长按时有圆形进度条的效果,如上图所示。
长按触发事件
微信小程序提供了 bindlongtap / bindlongpress 事件来捕捉用户长按事件,但是固定了一个时间,用户长按超过这个时间后才会触发,所以我们要手动捕捉用户按下和松开的事件、计算长按时间。
bindlongpress: 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发
长按时长(ms)= 松开时间 - 按下时间
我们首先配置 View: bindtap="btnTap" bindtouchstart="btnTouchStart" bindtouchend="btnTouchEnd"
JS中处理事件:
btnTouchStart(e) {
var that = this
that.setData({
btnTouchStartAt: e.timeStamp,
})
},
btnTouchEnd(e) {
var that = this
that.setData({
btnTouchEndAt: e.timeStamp,
})
},
btnTap() {
var that = this
var touchTime = that.data.sosTouchEndAt - that.data.sosTouchStartAt
console.log(that.data.sosTouchEndAt, that.data.sosTouchStartAt, touchTime)
if (touchTime > 1600) {
// 如果 > 1.6s
} else if (touchTime < 100) {
// 如果 < 100ms
}
},
按钮进度条动画
小程序旧版 Canvas 动画已弃用,所以目前能在网上找到的都不能直接用。
参考小程序文档-Canvas 2D迁移指南:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/canvas-legacy-migration.html
以及canvas画布文档: https://developers.weixin.qq.com/miniprogram/dev/framework/ability/canvas.html
CSS:
.container .circle-box {
left: calc( 50% - 100rpx );
bottom: -20rpx;
position: absolute;
height: 220rpx;
pointer-events: none;
}
.container .circle {
position: absolute;
left: -20rpx;
right: 20rpx;
margin: auto;
height: 240rpx;
width: 240rpx;
}
.container .sosbtn {
left: calc( 50% - 100rpx );
bottom: -20rpx;
position: absolute;
border-radius: 50%;
background-color: #F44336;
height: 200rpx;
width: 200rpx;
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
}
JS:
// 在 touchstart 事件中加入
that.setData({
sosTouchAnimationHandle: setInterval(() => {
if (that.data.nowDeg < 60 && that.data.nowDeg != -1) {
that.drawCircle(that.data.nowDeg)
that.setData({
nowDeg: that.data.nowDeg + 1
})
} else {
clearInterval(that.data.sosTouchAnimationHandle)
}
}, 50)
})
// setInterval 是为了防抖,不知道为什么长按后会再触发一次 导致已经松开了动画仍在继续。
// 在 touchend 事件中加入
setTimeout(() => {
clearInterval(that.sosTouchAnimationHandle)
}, 100)
that.setData({
nowDeg: -1,
})
that.createSelectorQuery()
.select('#canvasArcCir')
.fields({
node: true,
size: true
})
.exec((res) => {
const canvas = res[0].node
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, 200, 200);
})
setTimeout(() => {
that.setData({
nowDeg: 0
})
}, 500)
// 核心代码 canvas 绘制圆形进度条
drawCircle: function (nowDeg = false) {
var that = this;
function drawArc(s, e) {
that.createSelectorQuery()
.select('#canvasArcCir')
.fields({
node: true,
size: true
})
.exec((res) => {
const canvas = res[0].node
const renderWidth = res[0].width
const renderHeight = res[0].height
const ctx = canvas.getContext('2d')
const dpr = wx.getWindowInfo().pixelRatio
canvas.width = renderWidth * dpr
canvas.height = renderHeight * dpr
ctx.scale(dpr, dpr)
ctx.fillStyle = 'white';
ctx.clearRect(0, 0, 200, 200);
var x = renderWidth / 2,
y = renderWidth / 2,
radius = renderWidth / 2 - 5;
ctx.lineWidth = 5;
ctx.strokeStyle = '#FF5252';
ctx.lineCap = 'round';
ctx.beginPath();
ctx.arc(x, y, radius, s, e, false);
ctx.stroke()
})
}
if (nowDeg < 60) {
var initAngle = 1.5 * Math.PI // [初始角位置]1.5π 应该从12点方向开始 当然也可以自行替换
var endAngle = nowDeg * 4 * Math.PI / 60 + initAngle; // 4 可以替换 越大每次角度越大
drawArc(initAngle, endAngle)
}