Project Build – Reaction Timer Recap

Create Project

$ vue create reaction-timer

Open Project in VSC

Start Server

$ npm run serve

Create Component Files

Block.vue
Results.vue

Initialize Component Files

Type vue in editor and select <vue> with default vue.

Create App.vue

<template>
  <h1>Ninja Reaction Timer</h1>
  <button @click="start" v-bind:disabled="isPlaying">play</button>
  <Block v-if="isPlaying" :delay="delay" @end="endGame"></Block>
  <Results v-if="displayResults" :score="score"></Results>
</template>

<script>
import Block from './components/Block.vue'
import Results from './components/Results.vue'

export default {
  name: 'App',
  data() {
    return {
      isPlaying: false,
      delay: null,
      score: null,
      displayResults: false
    }
  },
  components: {
    Block,
    Results
  },
  methods: {
    start() {
      this.delay = 2000 + Math.random() * 5000
      this.isPlaying = true
      this.displayResults = false;
    },
    endGame(reactionTime) {
      this.score = reactionTime
      this.isPlaying = false
      this.displayResults = true
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #444;
  margin-top: 60px;
}
</style>

Create Block.vue

<template>
  <div v-if="showBlock" class="block" @click="stopTimer">
      click me
  </div>
</template>

<script>
export default { 
    props: ['delay'],
    data() {
        return {
            showBlock: false,
            timer: null,
            reactionTime: 0
        }
    },
    mounted() {
        setTimeout(() => {
            this.showBlock = true
            this.startTimer()
        }, this.delay)
    },
    methods: {
        startTimer() {
            this.timer = setInterval(() => {
                this.reactionTime += 10;
            }, 10)
        },
        stopTimer() {
            clearInterval(this.timer)
            console.log(this.reactionTime)
            this.$emit('end', this.reactionTime)
        }
    }
}
</script>

<style>
.block {
    width: 400px;
    border-radius: 20px;
    background: #0faf87;
    color: white;
    text-align: center;
    padding: 100px 0;
    margin: 40px auto;
}
</style>

Create Results.vue

<template>
    <p>Reaction Time: {{ score }} milliseconds</p>
    <p>Rank: {{ rank }} </p>
</template>

<script>
export default {
    props: ['score'],
    data() {
        return {
            rank: null
        }
    },
    mounted() {
        if (this.score< 250) {
            this.rank = 'Ninja fingers'
        }
        else if (this.score < 400) {
            this.rank = 'Rapid reflexes'
        }
        else {
            this.rank = 'Snail pace'
        }
    }
}
</script>

<style>

</style>

Summary of Techniques

  • Use v-if to conditionally display child components in main app component.
  • Define props in child component to allow parent component to pass in data (via component attributes) to child component.
  • Use hooks in child component to perform tasks at certain point (e.g. mounted) in the component life-cycle.
  • Pass data from the child component back to the parent component via custom event when calling this.$emit(‘event-name’, data).
  • Receive data from child component by registering handler on child component for custom-event emitted by the child component.  Received data is automatically passed as argument to the handler (e.g. handler(data) {…})

© 2022, Eric.

Leave a Reply

Your email address will not be published. Required fields are marked *