Прогрессбар на секундах с бордером на блоке
Как реализовать "прогрессбар" на 90 секунд с border, который будет обозначать сколько секунд закончилось. Если 90 вышло - значит border заполнен полностью по кругу. Border заполнения можно реализовать красный
.modal-timer__loader-circle {
display: block;
margin: 0 auto;
width: 140px;
height: 140px;
background: #E4F5FD;
border-radius: 50%;
border: 10px solid #DBF1FB;
}
.modal-timer__loader-title{
font-style: normal;
font-weight: bold;
font-size: 21px;
line-height: 29px;
text-align: center;
color: #6654A4;
padding-top: 28px;
margin: 0px 8px;
}
.modal-timer__loader-seconds {
font-style: normal;
font-weight: bold;
font-size: 21px;
line-height: 29px;
text-align: center;
color: #63C587;
flex: none;
order: 1;
flex-grow: 0;
margin: 0px 8px;
}
<div class="modal-timer__loader">
<div class="modal-timer__loader-circle">
924892347
</div>
<div class="modal-timer__loader-title">
{{'СODE'}}
</div>
<div class="modal-timer__loader-seconds">
00:90
</div>
<button
class="button-done"
type="main"
data-test="withdraw-submit"
>
{{ 'Done' }}
</button>
</div>
Ответы (1 шт):
Автор решения: MoloF
→ Ссылка
Чтобы создать анимацию заполнения круга можно воспользоваться SVG, в частности тегом circle и парочкой атрибутов: stroke-dasharray и stroke-dashoffset.
Все остальное это легкие математические операции и все.
Это простой вариант с анимацией на CSS, вариант анимации на JS с помощью lerp и requestAnimationFrame будет выглядеть получше, но это самый-самый простой вариант.
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: "#app",
data: {
total_seconds: 10,
seconds_left: 10,
interval_id: null,
complete: false,
circle_path_length: 0,
},
computed: {
seconds() {
return this.seconds_left.toString().padStart(2, '0');
}
},
mounted() {
const circleElement = this.$refs.circle;
this.circle_path_length = circleElement.getTotalLength();
circleElement.setAttribute('stroke-dasharray', this.circle_path_length);
circleElement.setAttribute('stroke-dashoffset', this.circle_path_length);
this.start();
},
beforeDestroy() {
clearInterval(this.interval_id);
},
methods: {
start() {
if (this.interval_id) return;
this.complete = false;
this.seconds_left = this.total_seconds;
this.interval_id = setInterval(this.update, 1000);
},
update() {
this.seconds_left--;
if (this.seconds_left < 1) this.finish();
const percent = this.total_seconds / this.seconds_left;
const path_length = this.circle_path_length / percent;
this.$refs.circle.setAttribute('stroke-dashoffset', path_length);
},
finish() {
clearInterval(this.interval_id);
this.interval_id = null;
this.complete = true;
}
}
})
body {
background: #20262E;
padding: 20px;
}
#app {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
width: 35%;
}
svg {
width: 100%;
height: 100%;
}
svg circle {
stroke-linecap: round;
stroke: #2980b9;
stroke-width: 10;
fill: #3498db;
transition: all 1s linear;
}
svg circle.complete {
stroke: #27ae60;
fill: #2ecc71;
}
svg text {
fill: #fff;
font-size: 35px;
text-anchor: middle;
dominant-baseline: central;
font-family: Helvetica, sans-serif;
letter-spacing: 2px;
}
#app button {
border: 10px solid #f39c12;
padding: 10px 25px;
background-color: #f1c40f;
border-radius: 50px;
color: #fff;
position: absolute;
left: 50%;
top: 100%;
transform: translateX(-50%);
outline: none;
margin-top: 10px;
transition: all .2s;
}
#app button.complete {
border: 10px solid #9b59b6;
background-color: #8e44ad;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<svg viewBox="0 0 100 100">
<circle
ref="circle"
cx="50"
cy="50"
r="45"
:class="{ complete }"
/>
<text x="50" y="50">{{ seconds }}</text>
</svg>
<button @click="start" :class="{ complete }">START</button>
</div>