Build a Countdown app with Vue.js using Composition API

Build a Countdown app with Vue.js using Composition API

·

5 min read

Recently I started learning Vue.js, and to my luck, it was being taught at the Sailscast community workshop. In the workshop, we were asked to build a countdown watch as a take-home assignment. Recognizing the value of documenting my journey, I decided to write this article.

This article will guide you through the process of building a countdown timer. and allow us to dive into fundamental Vue.js concepts, such as computed, unmounted, and onBeforeMount.

Let's get right into it!

The article assumes that you are familiar with HTML, CSS, JavaScript and a bit of Vue, which is a JavaScript framework.

Step 1: Setting up the project

  1. Install Node.JS: Vue.js relies on Node.js so make sure you have it installed on your local machine. You can download it from the Node.js website.

  2. Install Vue.js: Vue CLI is a command-line tool that helps you create and manage Vue.js projects effortlessly. Open your terminal or command prompt and run this command npm install -g @vue/cli -g @vue/ to install Vue CLI globally

  3. Installing the CLI will prompt you to create a new VUE project with the command

    vue create countdown-project and then navigate to the project directory via cd countdown-project.

  4. Run npm run serve to see your project in action.

Step 2: Create a Countdown Timer Component

In this step, you'll create a Vue component that handles the logic for the countdown timer using the Composition API, which offers a more organized and efficient way to manage component state and logic.

  1. Create the Component: Inside your project directory, navigate to the src/components folder (create it if it doesn't exist) and create a new file named CountdownTimer.vue.

  2. Edit the CountdownTimer.vue File: Open the CountdownTimer.vue file you just created in your code editor, and let's start building the component.

Inside the component, i.e, CountdownTimer.vue file you just created, add the skeletal structure for a Vue app to start building the logic which is:

<script>

The script setup section contains our javascript code/logic and we're using the Composition API to manage the component's logic.

</script>

<template>

The template section contains the HTML structure of the component.

</template>

<style scoped>

And this setup as you see clearly, handles the styling of this particular component.

</style>

Step 3: The Logic

  1. To build this app, you would first import statements from specific functions for the vue composition API like so:
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';

These statements are all reactive functions used to manage the state and lifecycle of the component.

  1. Next up, you would decide the target date and time you’re counting down to and store or declare a variable for it. You would also need to find the difference between your current time and target date.

In my case(this tutorial), I’m counting down to the end of the year as I’m manifesting something lol so copy the code below into your editor.

export default {
 setup() {
   const targetTime = new Date("2023-12-31T23:59:59").getTime();
   const currentTime = ref(new Date().getTime());
   const timeRemaining = ref(targetTime - currentTime.value);
  1. You would calculate the days, hours, minutes and seconds remaining until the target time as you’ll be using the timeRemaining value to perform these calculations and format the results as a string like so:👇
  1.  const formattedTime = computed(() => {
    
          const seconds = Math.floor(timeRemaining.value / 1000);
    
          const minutes = Math.floor(seconds / 60);
    
          const hours = Math.floor(minutes / 60);
    
          const days = Math.floor(hours / 24);
    
          return ${days}d ${hours % 24}h ${minutes % 60}m ${seconds % 60}s;
    
        });
    

    4. In this next step, you would create a function that updates the currentTime and recalculates the timeRemaining. of the timer by keeping the seconds In this case, you’ll use the Math. max(0, ...) to ensure that timeRemaining never becomes negative by updating the seconds to keep the timer going.

function updateTimer() {

     currentTime.value = new Date().getTime();

     timeRemaining.value = Math.max(0, targetTime - currentTime.value);

   }
  1. Finally, you’ll be using the lifecycle hook provided by Vue. The onMounted lifecycle hook runs after the component has been mounted to the DOM. Inside it, a setInterval is used to call the updateTimer function every second (1000 milliseconds), effectively updating the timer display. While the onBeforeUnmount lifecycle hook is triggered just before the component is unmounted. It clears the interval using clearInterval to prevent memory leaks.
  1.  let intervalId;
    
        onMounted(() => {
    
          intervalId = setInterval(updateTimer, 1000);
    
        });
    
        onBeforeUnmount(() => {
    
          clearInterval(intervalId);
    
        });
    

Thereafter, you use the return keyword to return the whole process into the formatted function like so: 👇

return {

     formattedTime,

   };

This is what your code should look like in the script section:👇

<script>

import { ref, computed, onMounted, onBeforeUnmount } from "vue";

export default {

 setup() {

   const targetTime = new Date("2023-12-31T23:59:59").getTime();

   const currentTime = ref(new Date().getTime());

   const timeRemaining = ref(targetTime - currentTime.value);

   const formattedTime = computed(() => {

     const seconds = Math.floor(timeRemaining.value / 1000);

     const minutes = Math.floor(seconds / 60);

     const hours = Math.floor(minutes / 60);

     const days = Math.floor(hours / 24);

     return ${days}d ${hours % 24}h ${minutes % 60}m ${seconds % 60}s;

   });

   let intervalId;

   onMounted(() => {

     intervalId = setInterval(updateTimer, 1000);

   });

   onBeforeUnmount(() => {

     clearInterval(intervalId);

   });

   function updateTimer() {

     currentTime.value = new Date().getTime();

     timeRemaining.value = Math.max(0, targetTime - currentTime.value);

   }

   return {

     formattedTime,

   };

 },

};

</script>

Step 4: Rendering and Styling

Now, that you’re done with the logic of the app, you have to render it to the HTML like so:👇

<template>
 <div class="countdown">
   <div class="timer">
     {{ formattedTime }}
   </div>
 </div>
</template>

Worthy to note that can you could integrate the countdown component into your main vue instance if you want, like so: 👇

<template>

  <div id="app">

    <CountdownTimer />

  </div>

</template>


<script>

import { createApp } from 'vue';

import CountdownTimer from './components/CountdownTimer.vue';


createApp({

  components: {

    CountdownTimer,

  },

}).mount('#app');

</script>

Or, you could go ahead and just style your app with either tailwind or CSS. In this tutorial, I’ll be using CSS to create basic styling. Check the code out:



.countdown {
 display: flex;
 justify-content: center;
 align-items: center;
 height: 100vh;
 background-color: aqua;
}
.timer {
 font-size: 2rem;
 display: flex;
 align-items: center;
 padding: 1rem;
 background-color: #333;
 color: #fff;
 border-radius: 0.5rem;
}

This is what the countdown timer looks like:

Conclusion

Congratulations! 🎊 You have successfully built a countdown app with Vue.js. This accomplishment marks just the beginning of your potential to create even more amazing projects. Keep coding, keep learning, and keep pushing the boundaries of what's possible