uniapp小程序利用
canvas2d
实现根据指定时间动态画圆环效果
调用
<view class="dubbing-control" :style="{'width':recordWidth,'height':recordWidth}">
<dubbing-button v-if="show" :width.sync="recordWidth" :size='71' ref="record" @startRecord="onClickHandle" @stopRecord="onClickHandle" :duration="recordConfig.duration">dubbing-button>
<image v-else :style="{'width':'142rpx','height':'142rpx','opacity':'0.4'}" src="../static/xgn/record_img.png">image>
view>
<script>
export default {
data() {
return {
show:true,
recordWidth:'88px',
recording:'start',
}
},
methods:{
onClickHandle(recording){
this.recording = recording;
if (Object.is(this.recording, 'proceed')) {
this.$refs.record.startRecord();
this.recording = 'proceed';
} else {
this.recording = 'end';
}
}
}
}
script>
组件
<template>
<view class="dubbing-button">
<view :style="{width: (2*radius+16)+'px', height:(2*radius+16)+'px'}" :class="['record-button',shadowShow ? 'record-button-shadow' : ''] " @touchstart="onClickHandle">
<canvas class="progress_bg" v-if="Object.is(recording, 'proceed')" type="2d" id="cpbar" canvas-id="cpbar"
:style="{width: (2*radius+16)+'px', height:(2*radius+16)+'px'}" >canvas>
<image v-if="recording=='proceed'" src="../static/xgn/recording_img.gif" :style="{width: 2*radius+'px', height:2*radius+'px'}">
<image v-else src="../static/xgn/record_img.png" :style="{width: 2*radius+'px', height:2*radius+'px'}">
image>
view>
view>
template>
<script>
export default {
name: 'record-button',
data() {
return {
radius: 0,
eAngle: 0,
interval: null,
deviceWidth: 0,
recording: 'start',
canvasContext: null,
shadowShow: false,
};
},
props: {
duration: {
type: Number,
default () {
return 20000;
}
},
size: {
type: Number,
default () {
return 44;
}
},
width:{
type:String,
default:''
},
},
created() {
const res = uni.getSystemInfoSync();
this.deviceWidth = res.windowWidth;
this.radius = this.getPointValue(this.size);
this.width =(2*this.radius+16)+'px';
this.$emit('update:width',this.width)
},
mounted() {
},
methods: {
async onClickHandle() {
console.log('button this.recording',this.recording);
if (!Object.is(this.recording, 'proceed')) {
this.shadowShow = true;
}
if (Object.is(this.recording, 'proceed')) {
this.shadowShow = false;
this.stopRecord();
} else {
if(this.shadowShow){
this.$emit('startRecord', 'proceed');
}
}
},
startRecord() {
console.log('开始了')
this.recording = 'proceed';
let that = this;
this.shadowShow = false;
this.drawCircle();
},
stopRecord(status) {
status ? this.recording = 'start' : this.recording = 'end';
let that = this;
this.$emit('stopRecord', 'end');
clearTimeout(that.interval);
this.interval = null;
this.canvasContext && this.clearCicle();
this.eAngle = 0;
},
drawCircle: function() {
this.$nextTick(()=>{
const query = uni.createSelectorQuery().in(this);
query.select('#cpbar').fields({
node: true,
size: true
}).exec(res => {
console.log('res',res);
if(res){
const canvas = res[0].node;
const ctx = canvas.getContext("2d");
const dpr = wx.getSystemInfoSync().pixelRatio;
canvas.width = res[0].width * dpr;
canvas.height = res[0].height * dpr;
ctx.scale(dpr, dpr);
this.canvasContext = ctx;
this.drawCircleAction();
}
})
})
},
drawCircleAction(){
this.eAngle += 2 * Math.PI / (this.duration / 100);
this.canvasContext.lineWidth = 4;
this.canvasContext.strokeStyle = '#FE9B2F';
this.canvasContext.lineCap = 'butt';
this.canvasContext.beginPath();
this.canvasContext.arc(this.radius + 8, this.radius + 8, this.radius + 4, 0, this.eAngle , false);
this.canvasContext.stroke();
this.canvasContext.closePath();
if (this.eAngle >= 2 * Math.PI) {
this.stopRecord();
} else {
let that = this;
clearTimeout(that.interval);
this.interval = setTimeout(that.drawCircleAction, 100);
}
},
clearCicle() {
this.canvasContext.clearRect(0, 0, 2 * this.radius + 16, 2 * this.radius + 16);
},
getPointValue(val) {
return Math.floor(val * this.deviceWidth / 750);
},
},
destroyed() {
this.stopRecord();
}
}
script>
<style lang="scss" scoped>
.record-button {
position: relative;
image {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
.progress_bg {
position: absolute;
top: 0;
left: 0;
z-index: 1;
transform: rotate(-90deg);
}
}
.record-button-shadow{
image {
opacity: 0.4;
}
}
.popup_wrap {
width: 594rpx;
border-radius: 20rpx;
background: #fff;
box-sizing: border-box;
padding-top: 48rpx;
display: flex;
flex-direction: column;
box-sizing: border-box;
box-shadow: 0rpx 6rpx 20rpx 0rpx rgba(255, 214, 170, 0.9);
.popup_title {
font-size: 34rpx;
font-weight: 500;
color: #283445;
text-align: center;
margin-bottom: 48rpx;
padding: 0 20rpx;
box-sizing: border-box;
}
.popup_footer {
height: 88rpx;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 0 20rpx;
box-sizing: border-box;
view {
flex: 1;
border-top: 2rpx solid #dcdcdc;
text-align: center;
font-size: 32rpx;
padding: 22rpx 0;
box-sizing: border-box;
text {
display: block;
height: 50rpx;
}
}
view.popup_footer_confirm {
color: #283445;
text {
border-left: 2rpx solid #dcdcdc;
}
}
view.popup_footer_cancel {
color: #7e94b1;
}
}
}
style>