Skip to content

Timer

Template

HTML
<template>
	<label>
		Elapsed Time: <progress :value="progressRate"></progress>
	</label>

	<div>{{ (elapsed / 1000).toFixed(1) }}s</div>

	<div>
		Duration: <input type="range" v-model="duration" min="1" max="30000">
		{{ (duration / 1000).toFixed(1) }}s
	</div>

	<button @click="reset">Reset</button>
</template>
<template>
	<label>
		Elapsed Time: <progress :value="progressRate"></progress>
	</label>

	<div>{{ (elapsed / 1000).toFixed(1) }}s</div>

	<div>
		Duration: <input type="range" v-model="duration" min="1" max="30000">
		{{ (duration / 1000).toFixed(1) }}s
	</div>

	<button @click="reset">Reset</button>
</template>

Composition API

It's an example for <scipt setup>.

JavaScript
import { ref, onUnmounted, computed } from 'vue'
const duration = ref(15 * 1000)
const elapsed = ref(0)

let lastTime
let handle

const update = () => {
  elapsed.value = performance.now() - lastTime
  if (elapsed.value >= duration.value) {
    cancelAnimationFrame(handle)
  } else {
    handle = requestAnimationFrame(update)
  }
}

const reset = () => {
  elapsed.value = 0
  lastTime = performance.now()
  update()
}

const progressRate = computed(() =>
  Math.min(elapsed.value / duration.value, 1)
)

reset()

onUnmounted(() => {
  cancelAnimationFrame(handle)
})
import { ref, onUnmounted, computed } from 'vue'
const duration = ref(15 * 1000)
const elapsed = ref(0)

let lastTime
let handle

const update = () => {
  elapsed.value = performance.now() - lastTime
  if (elapsed.value >= duration.value) {
    cancelAnimationFrame(handle)
  } else {
    handle = requestAnimationFrame(update)
  }
}

const reset = () => {
  elapsed.value = 0
  lastTime = performance.now()
  update()
}

const progressRate = computed(() =>
  Math.min(elapsed.value / duration.value, 1)
)

reset()

onUnmounted(() => {
  cancelAnimationFrame(handle)
})

If you are using the Option API style with setup(), you need to return certain variables and computed properties:

JavaScript
export default {
	setup() {
		return {
			duration,
			elapsed,
			progressRate,
			reset
		}
	}
}
export default {
	setup() {
		return {
			duration,
			elapsed,
			progressRate,
			reset
		}
	}
}

Options API

JavaScript
export default {
  data() {
    return {
      duration: 15 * 1000,
      elapsed: 0
    }
  },
  created() {
    this.reset()
  },
  unmounted() {
    cancelAnimationFrame(this.handle)
  },
  computed: {
    progressRate() {
      return Math.min(this.elapsed / this.duration, 1)
    }
  },
  methods: {
    update() {
      this.elapsed = performance.now() - this.lastTime
      if (this.elapsed >= this.duration) {
        cancelAnimationFrame(this.handle)
      } else {
        this.handle = requestAnimationFrame(this.update)
      }
    },
    reset() {
      this.elapsed = 0
      this.lastTime = performance.now()
      this.update()
    }
  }
}
export default {
  data() {
    return {
      duration: 15 * 1000,
      elapsed: 0
    }
  },
  created() {
    this.reset()
  },
  unmounted() {
    cancelAnimationFrame(this.handle)
  },
  computed: {
    progressRate() {
      return Math.min(this.elapsed / this.duration, 1)
    }
  },
  methods: {
    update() {
      this.elapsed = performance.now() - this.lastTime
      if (this.elapsed >= this.duration) {
        cancelAnimationFrame(this.handle)
      } else {
        this.handle = requestAnimationFrame(this.update)
      }
    },
    reset() {
      this.elapsed = 0
      this.lastTime = performance.now()
      this.update()
    }
  }
}