'How do I create a simple 10 seconds countdown in Vue.js
I want to do a simple countdown from 10 to 0
I found solution online using normal javascript but let say I want to do it in Vue . The solution in Jquery
Create a simple 10 second countdown
<template>
{{ countDown }}
</template>
<script>
export default {
computed: {
countDown() {
// How do i do the simple countdown here?
}
}
}
</script>
How do I recreate the same functionality in Vue.js?
Thanks
Solution 1:[1]
Please check if this works for you.
<template>
{{ countDown }}
</template>
<script>
export default {
data () {
return {
countDown: 10
}
},
methods: {
countDownTimer () {
if (this.countDown > 0) {
setTimeout(() => {
this.countDown -= 1
this.countDownTimer()
}, 1000)
}
}
},
created () {
this.countDownTimer()
}
}
</script>
Solution 2:[2]
Whilst the accepted answer works, and is great, it can actually be achieved in a slightly simpler way by utilising Vue.js watchers:
<template>
{{ timerCount }}
</template>
<script>
export default {
data() {
return {
timerCount: 30
}
},
watch: {
timerCount: {
handler(value) {
if (value > 0) {
setTimeout(() => {
this.timerCount--;
}, 1000);
}
},
immediate: true // This ensures the watcher is triggered upon creation
}
}
}
</script>
The benefit of using this method is that the timer can be immediately reset by simply setting the value of timerCount
.
If you would like to play/pause the timer, then you can achieve this like so (note - this is not a perfect solution as it will round to the nearest second):
<template>
{{ timerCount }}
</template>
<script>
export default {
data() {
return {
timerEnabled: true,
timerCount: 30
}
},
watch: {
timerEnabled(value) {
if (value) {
setTimeout(() => {
this.timerCount--;
}, 1000);
}
},
timerCount: {
handler(value) {
if (value > 0 && this.timerEnabled) {
setTimeout(() => {
this.timerCount--;
}, 1000);
}
},
immediate: true // This ensures the watcher is triggered upon creation
}
}
methods: {
play() {
this.timerEnabled = true;
},
pause() {
this.timerEnabled = false;
}
}
}
</script>
Solution 3:[3]
Here is a component I made for a countdown timer :
<template>
<div>
<slot :hour="hour" :min="min" :sec="sec"></slot>
</div>
</template>
<script>
export default {
props : {
endDate : { // pass date object till when you want to run the timer
type : Date,
default(){
return new Date()
}
},
negative : { // optional, should countdown after 0 to negative
type : Boolean,
default : false
}
},
data(){
return{
now : new Date(),
timer : null
}
},
computed:{
hour(){
let h = Math.trunc((this.endDate - this.now) / 1000 / 3600);
return h>9?h:'0'+h;
},
min(){
let m = Math.trunc((this.endDate - this.now) / 1000 / 60) % 60;
return m>9?m:'0'+m;
},
sec(){
let s = Math.trunc((this.endDate - this.now)/1000) % 60
return s>9?s:'0'+s;
}
},
watch : {
endDate : {
immediate : true,
handler(newVal){
if(this.timer){
clearInterval(this.timer)
}
this.timer = setInterval(()=>{
this.now = new Date()
if(this.negative)
return
if(this.now > newVal){
this.now = newVal
this.$emit('endTime')
clearInterval(this.timer)
}
}, 1000)
}
}
},
beforeDestroy(){
clearInterval(this.timer)
}
}
</script>
Solution 4:[4]
Make it a component so you can re-use it.
<body>
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script>
Vue.component('counter', {
template: '<button v-on:click="countDownTimer()">{{ countDown }}</button>',
data: function () {
return {
countDown: 10,
countDownTimer() {
if (this.countDown > 0) {
setTimeout(() => {
this.countDown -= 1
this.countDownTimer();
}, 1000)
}
}
}
}
})
const app = new Vue({
el: '#app'
})
</script>
</body>
Solution 5:[5]
In case if anyone uses Luxon's DateTime object instead of native JS's Date object.
<template>
<span v-if="timer">
{{ timeCalculated }}
</span>
</template>
<script>
import { DateTime } from 'luxon'
export default {
name: 'CountDownTimer',
props: {
endDate: {
type: String,
required: true
}
},
data () {
return {
now: DateTime.local(),
timer: null
}
},
computed: {
timeCalculated () {
const endDateDateTimeObj = DateTime.fromISO(this.endDate)
const theDiff = endDateDateTimeObj.diff(this.now, ['hours', 'minutes', 'seconds'])
return `${theDiff.hours}:${theDiff.minutes}:${Math.round(theDiff.seconds)}`
}
},
watch: {
endDate: {
immediate: true,
handler (endDateTimeStr) {
const endDateTimeObj = DateTime.fromISO(endDateTimeStr)
if (this.timer) {
clearInterval(this.timer)
}
this.timer = setInterval(() => {
this.now = DateTime.local()
if (this.now > endDateTimeObj) {
this.now = endDateTimeObj
clearInterval(this.timer)
}
}, 1000)
}
}
},
beforeDestroy () {
clearInterval(this.timer)
}
}
</script>
In my case endDate
has String type because the value is restored from JSON. You can easily change it to the original DateTime object.
Solution 6:[6]
Use dates.
<template>
<div>{{ time }}</div>
</template>
<script>
export default {
name: 'Timer',
props: ['seconds'],
data: () => ({
interval: undefined,
end: new Date(0, 0, 0),
current: new Date(0, 0, 0, 0, 0, this.seconds)
}),
computed: {
time: {
get() {
return this.current.getSeconds();
},
set(d) {
this.current = new Date(0, 0, 0, 0, 0, this.current.getSeconds() + d);
}
}
},
methods: {
countDown() {
this.end >= this.current
? clearInterval(this.interval)
: (this.time = -1);
}
},
created() {
this.interval = setInterval(this.countDown, 1000);
}
};
</script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | grim |
Solution 2 | |
Solution 3 | user8805101 |
Solution 4 | Rafiq |
Solution 5 | TitanFighter |
Solution 6 | Sebastian Scholl |