<script type="text/x-templete" id="progress-circle">
<div class="progress-circle">
	<div class="progress-circle-inner" :style="innerStyle">
		<svg viewBox="0 0 100 100">
			<circle class="progress-circle-trail" cx="50" cy="50" r="40" fill="none" :style="trailStyle"></circle>
			<circle class="progress-circle-path" cx="50" cy="50" r="40" fill="none" :style="strokeStyle"></circle>
		</svg>
	</div>
	<span class="progress-circle-text"><slot><slot></span>
</div>
</script>


<script type="text/x-templete" id="main-page">
<div>
	<div class="demo1">
		<progress-circle
			:percent="percent"
			:strokeColor="strokeColor"
			:strokeWidth="strokeWidth"
			:size="size"
		>
			<div v-show="percent!=100">{{percent}}%</div>
			<div class="progress-success-iconwrap" :class="{active: percent===100}">
				<svg viewBox="0 0 80 60">
					<path d="M10,30 l20,20 l40,-40" fill="none" :stroke="strokeColor" stroke-width="4" stroke-linecap="round" id="successPath" :style="pathStyle" class="progress-success-icon"></path>
				</svg>
			</div>
	</progress-circle>
	</div>
	<div class="text-center">
		<div class="btn-group" role="group" aria-label="Basic example">
			<button type="button" class="btn btn-outline-primary btn-sm" @click="dec">-</button>
			<button type="button" class="btn btn-outline-primary btn-sm" @click="add">+</button>
		</div>
	</div>
</div>
</script>

<div id="app"></div>

.demo1 {
	height: 300px;
	display: flex;
	justify-content: center;
	align-items: center;
}

.progress-circle {
	display:inline-block;
	position: relative;
	&-inner{
		line-height: 1;
		background-color: transparent;
		display: inline-block;
    width: 100%;
    border-radius: 100px;
    vertical-align: middle;
		transform: rotate(-90deg);
	}
	&-trail,&-path{
		stroke-linecap: round;
		transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s;
	}
	&-text {
		display: block;
    position: absolute;
    width: 100%;
    text-align: center;
    line-height: 1;
		font-size: 1.4em;
		color: rgba(0,0,0,.65);
    top: 50%;
    transform: translateY(-50%);
    left: 0;
    font-family: tahoma;
    margin: 0;
	}
}

.progress-success {
	&-iconwrap{
		width: 50px;
		display:none;
		&.active{
			display: inline-block;
			.progress-success-icon{
				animation: ani-success-effect .3s ease both;
			}
		}
	}
	
}
@keyframes ani-success-effect{
	0% { stroke-dashoffset: 110%; opacity:0; }
	100% { stroke-dashoffset: 0; opacity:1; }
}
View Compiled
Vue.component('progress-circle', {
	data:function(){
		return {
			len: Math.PI*2*40
		}
	},
	props: {
		'size': {
			type: Number,
			default: 100,
		},
		'percent':{
			type:Number,
			default: 0
		}, 
		'strokeWidth':{
			type:Number,
			default: 8
		}, 
		'strokeColor':{
			type:String,
			default: '#108EE9'
		}, 
		'trailColor':{
			type:String,
			default: '#F7F7F7'
		}, 
		'trailWidth':{
			type:Number,
			default: 8
		}
	},
  template: '#progress-circle',
	computed: {
		innerStyle: function(){
			return { width:`${this.size}px`, height: `${this.size}px`}
		},
		strokeStyle: function(){
			const currPercent = this.percent/100 * this.len;
			return {
				'stroke':this.strokeColor,
				'stroke-dasharray':`${currPercent}px, ${this.len}px`,
				'stroke-width': `${this.strokeWidth}px`,
			}
		},
		trailStyle: function(){
			return {
				'stroke':this.trailColor,
				'stroke-dasharray':`${this.len}px, ${this.len}px`,
				'stroke-width': `${this.trailWidth}px`,
			}
		},
	}
})

// start app
new Vue({
  el: '#app',
 	template: '#main-page',
  data: {
		percent:10,
		strokeColor: '#108EE9',
		strokeWidth: 5,
		size: 140,
		pathLen: 0,
  },
	methods:{
		add: function(){
			this.percent+=10;
			if(this.percent === 100){
				this.strokeColor = '#00A854';
			}
			if(this.percent>100) this.percent = 100;
		},
		dec: function(){
			this.percent-=10;
			this.strokeColor = '#108EE9';
			if(this.percent<0) this.percent = 0;
		},
	},
	mounted:function(){
		this.$nextTick(()=>{
			this.pathLen = document.getElementById('successPath').getTotalLength();
			// console.log(this.pathLen)
		})
	},
	computed:{
		pathStyle:function(){
			const offset = this.percent===100 ? 0 : this.pathLen;
			return {
				'stroke-dasharray': `${this.pathLen}px ${this.pathLen}px`,
			}
		}
	}
})
View Compiled
Rerun