Build a Vue.js Flip Digital Countdown Analog Clock in Javascript Full Project For Beginners

You are currently viewing Build a Vue.js Flip Digital Countdown Analog Clock in Javascript Full Project For Beginners
  • Post author:
  • Post category:Vue
  • Post comments:0 Comments

 

Welcome folks today in this blog post we will be building a vue.js flip digital countdown analog clock in javascript. All the full source code of the application is given below.

 

 

Get Started

 

 

In order to get started you need to make an index.html file and copy paste the following code

 

index.html

 

<script>console.clear();</script

 

 

And now make a style.css file and copy paste the following code

 

style.css

 

html {
     height: 100%;
}
 body {
     min-height: 100%;
     display: flex;
     justify-content: center;
     align-items: center;
     background: #EEE;
}
 .flip-clock {
     text-align: center;
     perspective: 600px;
     margin: 0 auto;
}
 .flip-clock *, .flip-clock *:before, .flip-clock *:after {
     box-sizing: border-box;
}
 .flip-clock__piece {
     display: inline-block;
     margin: 0 0.2vw;
}
 @media (min-width: 1000px) {
     .flip-clock__piece {
         margin: 0 5px;
    }
}
 .flip-clock__slot {
     font-size: 1rem;
     line-height: 1.5;
     display: block;
}
 .flip-card {
     display: block;
     position: relative;
     padding-bottom: 0.72em;
     font-size: 2.25rem;
     line-height: 0.95;
}
 @media (min-width: 1000px) {
     .flip-clock__slot {
         font-size: 1.2rem;
    }
     .flip-card {
         font-size: 3rem;
    }
}
 .flip-card__top, .flip-card__bottom, .flip-card__back-bottom, .flip-card__back::before, .flip-card__back::after {
     display: block;
     height: 0.72em;
     color: #ccc;
     background: #222;
     padding: 0.23em 0.25em 0.4em;
     border-radius: 0.15em 0.15em 0 0;
     backface-visiblity: hidden;
     transform-style: preserve-3d;
     width: 1.8em;
}
 .flip-card__bottom, .flip-card__back-bottom {
     color: #FFF;
     position: absolute;
     top: 50%;
     left: 0;
     border-top: solid 1px #000;
     background: #393939;
     border-radius: 0 0 0.15em 0.15em;
     pointer-events: none;
     overflow: hidden;
     z-index: 2;
}
 .flip-card__back-bottom {
     z-index: 1;
}
 .flip-card__bottom::after, .flip-card__back-bottom::after {
     display: block;
     margin-top: -0.72em;
}
 .flip-card__back::before, .flip-card__bottom::after, .flip-card__back-bottom::after {
     content: attr(data-value);
}
 .flip-card__back {
     position: absolute;
     top: 0;
     height: 100%;
     left: 0%;
     pointer-events: none;
}
 .flip-card__back::before {
     position: relative;
     overflow: hidden;
     z-index: -1;
}
 .flip .flip-card__back::before {
     z-index: 1;
     animation: flipTop 0.3s cubic-bezier(.37,.01,.94,.35);
     animation-fill-mode: both;
     transform-origin: center bottom;
}
 .flip .flip-card__bottom {
     transform-origin: center top;
     animation-fill-mode: both;
     animation: flipBottom 0.6s cubic-bezier(.15,.45,.28,1);
}
 @keyframes flipTop {
     0% {
         transform: rotateX(0deg);
         z-index: 2;
    }
     0%, 99% {
         opacity: 1;
    }
     100% {
         transform: rotateX(-90deg);
         opacity: 0;
    }
}
 @keyframes flipBottom {
     0%, 50% {
         z-index: -1;
         transform: rotateX(90deg);
         opacity: 0;
    }
     51% {
         opacity: 1;
    }
     100% {
         opacity: 1;
         transform: rotateX(0deg);
         z-index: 5;
    }
}

 

 

And now make a script.js  file and copy paste the below code

 

script.js

 

Vue.filter('zerofill', function (value) {
  //value = ( value < 0 ? 0 : value );
  return ( value < 10 && value > -1 ? '0' : '' ) + value;
});

var Tracker = Vue.extend({
  template: `
  <span v-show="show" class="flip-clock__piece">
    <span class="flip-clock__card flip-card">
      <b class="flip-card__top">{{current | zerofill}}</b>
      <b class="flip-card__bottom" data-value="{{current | zerofill}}"></b>
      <b class="flip-card__back" data-value="{{previous | zerofill}}"></b>
      <b class="flip-card__back-bottom" data-value="{{previous | zerofill}}"></b>
    </span>
    <span class="flip-clock__slot">{{property}}</span>
  </span>`, 
  props: ['property','time'],
  data: () => ({
    current: 0,
    previous: 0,
    show: false
  }),
  
  events: {
    time(newValue) {
      
      if ( newValue[this.property] === undefined ) { 
        this.show = false; 
        return;
      }
      
      var val = newValue[this.property];
      this.show = true;
      
      val = ( val < 0 ? 0 : val );
      
      if ( val !== this.current ) {
  
        this.previous = this.current;
        this.current = val;
  
        this.$el.classList.remove('flip');
        void this.$el.offsetWidth;
        this.$el.classList.add('flip');
      }
      
    }
  },

});
  

  
var el = document.createElement('div');
document.body.appendChild(el);

var Countdown = new Vue({
  
  el: el,
  
  template: ` 
  <div class="flip-clock" data-date="2017-02-11" @click="update">
    <tracker 
      v-for="tracker in trackers"
      :property="tracker"
      :time="time"
      v-ref:trackers
    ></tracker>
  </div>
  `,

  props: ['date','callback'],

  data: () => ({
    time: {},
    i: 0,
    trackers: ['Days', 'Hours','Minutes','Seconds'] //'Random', 
  }),

  components: {
    Tracker
  },
  
  beforeDestroy(){
    if ( window['cancelAnimationFrame'] ) {
      cancelAnimationFrame(this.frame);
    }
  },
  
  watch: {
    'date': function(newVal){
      this.setCountdown(newVal);
    }
  },
  
  ready() {
    if ( window['requestAnimationFrame'] ) {
      this.setCountdown(this.date);
      this.callback = this.callback || function(){};
      this.update();
    }
  },
  
  methods: {
    
    setCountdown(date){
      
      if ( date ) {
        this.countdown = moment(date, 'YYYY-MM-DD HH:mm:ss');
      } else {
        this.countdown = moment().endOf('day');  //this.$el.getAttribute('data-date');
      }
    },
    
    update() {
      this.frame = requestAnimationFrame(this.update.bind(this));
      if ( this.i++ % 10 ) { return; }
      var t = moment(new Date());
      // Calculation adapted from https://www.sitepoint.com/build-javascript-countdown-timer-no-dependencies/
      if ( this.countdown ) { 
        
        t = this.countdown.diff(t);
        
        //t = this.countdown.diff(t);//.getTime();
        //console.log(t);
        this.time.Days = Math.floor(t / (1000 * 60 * 60 * 24));
        this.time.Hours = Math.floor((t / (1000 * 60 * 60)) % 24);
        this.time.Minutes = Math.floor((t / 1000 / 60) % 60);
        this.time.Seconds = Math.floor((t / 1000) % 60);
      } else {
        this.time.Days = undefined;
        this.time.Hours = t.hours() % 13;
        this.time.Minutes = t.minutes();
        this.time.Seconds = t.seconds();
      }
      
      this.time.Total = t;
      
      this.$broadcast('time',this.time);
      return this.time;
    }
  }
});

 

 

And now if you open index.html file inside the browser you will see the below screenshot

 

Leave a Reply