调用插件:

	<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 MP
	function setTimeout(t, cb, d) {
		if (d > 0) {
			var s = getDate().getTime();
			var fn = function () {
				if (getDate().getTime() - s > d) {
					cb && cb();
				} else
					t.requestAnimationFrame(fn);
			}
			fn();
		}
		else
			cb && cb();
	}
	//#endif

	function 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 MP
					setTimeout(function() {
						var timeStamp = +new Date();
						step(timeStamp);
					}, delay);
					//#endif
					//#ifdef MP
					setTimeout(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) % 4
		var pdeg = deg % 90
		var per = pdeg / 90 * 100
		if(ops[idx]) {
			return 'polygon(' + ops[idx](per) + ')'
		}
		else {
			return ''
		}
	}

	function setDeg(newValue, oldValue, ownerInstance, instance) {
		var odeg = oldValue * 360
		var deg = newValue * 360
		var offset = deg - odeg
		
		var 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 * offset
				var 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-1
			start: {
				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>

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐