调用插件:
<circle-progress-bar :pro="84/100" :border_back_color="'#297DFE'" :border_color="'#FB8F23'">{{84}}%</circle-progress-bar>
添加插件引用:
<script>import CircleProgressBar from '../../components/circle-progress-bar/circle-progress-bar.vue'export default {components: {Axxx,CircleProgressBar,},</script>
circle-progress-bar.vue
<template><view class="circle-progress-bar" :style="{width: sunit(size),height: sunit(size),}"><view class="circle" :change:prop="animateModule.pro" :prop="cpro":data-animate="animate":style="{transform: `rotate(${start * 360 + 45}deg)`,border: `${sunit(border_width)} solid ${border_color}`,}"></view><view class="bg" v-if="background":style="{background: background,}"></view><view class="border-back" v-if="border_back_color":style="{border: `calc(${sunit(border_width)} - 1px) solid ${border_back_color}`}"></view><view class="center"><slot :pro="cpro"></slot></view></view>
</template><script module="animateModule" lang="wxs">var Timing = {easeIn: function easeIn(pos) {return Math.pow(pos, 3);},easeOut: function easeOut(pos) {return Math.pow(pos - 1, 3) + 1;},easeInOut: function easeInOut(pos) {if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos, 3);} else {return 0.5 * (Math.pow(pos - 2, 3) + 2);}},linear: function linear(pos) {return pos;}};//#ifdef MPfunction setTimeout(t, cb, d) {if (d > 0) {var s = getDate().getTime();var fn = function () {if (getDate().getTime() - s > d) {cb && cb();} elset.requestAnimationFrame(fn);}fn();}elsecb && cb();}//#endiffunction Animation(opts) {opts.duration = typeof opts.duration === 'undefined' ? 1000 : opts.duration;opts.timing = opts.timing || 'linear';var delay = 17;function createAnimationFrame() {if (typeof setTimeout !== 'undefined') {return function(step, delay) {//#ifndef MPsetTimeout(function() {var timeStamp = +new Date();step(timeStamp);}, delay);//#endif//#ifdef MPsetTimeout(opts.instance, function () {var timeStamp = getDate()step(timeStamp);}, delay)//#endif};} else if (typeof requestAnimationFrame !== 'undefined') {return requestAnimationFrame;} else {return function(step) {step(null);};}};var animationFrame = createAnimationFrame();var startTimeStamp = null;var _step = function step(timestamp) {if (timestamp === null) {opts.onProcess && opts.onProcess(1);opts.onAnimationFinish && opts.onAnimationFinish();return;}if (startTimeStamp === null) {startTimeStamp = timestamp;}if (timestamp - startTimeStamp < opts.duration) {var process = (timestamp - startTimeStamp) / opts.duration;var timingFunction = Timing[opts.timing];process = timingFunction(process);opts.onProcess && opts.onProcess(process);animationFrame(_step, delay);} else {opts.onProcess && opts.onProcess(1);opts.onAnimationFinish && opts.onAnimationFinish();}};animationFrame(_step, delay);}function getPath(deg) {var path = '50% 50%'//各个锚点var ps = ['0% 0%', '100% 0%', '100% 100%', '0% 100%']var ps1 = path + ',' + ps[0]var ps2 = ps1 + ',' + ps[1]var ps3 = ps2 + ',' + ps[2]var ps4 = ps3 + ',' + ps[3]var ops = [function(per) { return ps1 + ',' + (per + '% 0%') },function(per) { return ps2 + ',' + ('100% ' + per + '%') },function(per) { return ps3 + ',' + (100 - per) + '% 100%' },function(per) { return ps4 + ',' + '0% ' + (100 - per) + '%' },]if (deg == 0) {return 'polygon(50% 50%, 50% 0%)'}else if (deg % 360 == 0) {return ''}var idx = parseInt(deg / 90) % 4var pdeg = deg % 90var per = pdeg / 90 * 100if(ops[idx]) {return 'polygon(' + ops[idx](per) + ')'}else {return ''}}function setDeg(newValue, oldValue, ownerInstance, instance) {var odeg = oldValue * 360var deg = newValue * 360var offset = deg - odegvar ds = instance.getDataset()if(!ds.animate) {var path = getPath(deg)instance.setStyle({'clip-path': path,})return}Animation({instance: ownerInstance,timing: 'easeInOut',duration: 300,onProcess: function onProcess(process) {var pdeg = odeg + process * offsetvar path = getPath(pdeg)var com = ownerInstance.selectComponent('.circle');com.setStyle({'clip-path': path,})},onAnimationFinish: function onAnimationFinish() {}});}module.exports = {pro: setDeg,}
</script><script>export default {props: {pro: {type: Number,default: 0},//起始位置 0-1start: {type: Number,default: 0,},//圆形大小size: {type: Number,default: 200},//线宽度border_width: {type: Number,default: 20},//线颜色border_color: {type: String,default: '#07C160',},//线背景色border_back_color: {type: String,},//中心内容背景色background: {type: String,},//单位unit: {type: String,default: 'rpx',},//是否启用动画animate:{type: Boolean,default: true,}},data() {return {cpro: 0,}},watch: {pro(val) {this.cpro = val}},mounted() {this.cpro = this.pro},methods: {sunit(num) {if(typeof num === 'number') {return num + this.unit}}}}
</script><style scoped lang="scss">.circle-progress-bar{position: relative;}.circle, .bg, .border-back {height: 100%;width: 100%;border-radius: 50%;position: absolute;box-sizing: border-box;}.circle{z-index: 1;}.border-back{height: calc(100% - 1px);width: calc(100% - 1px);left: 50%;top: 50%;transform: translate(-50%, -50%);}.point {position: absolute;border-radius: 50%;z-index: 1;}.center{position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);z-index: 2;}
</style>