LoginSignup
13
18

More than 5 years have passed since last update.

Vueで最初に作ったものがなぜかデジタル時計だったお話

Posted at

Vueに触れ始めて少し経ったある日、

「Vueも少しずつ慣れてきたし、何か一つ自分で作ってみようかな。
でもそんなに難しいのはまだ無理だし…。
とりあえず時計作るか!!」

というわけでこんな感じのものができました。

digital_clock.gif

少々ネタではありますが、学んだことを織り交ぜながら紹介していこうと思います。

構成図

digital_clock_parts_discription.PNG

図のようにコンポーネントを作って組み合わせていきます。

LightStick

オンで光ってオフで消える「光る棒!!」を作ります。

縦棒と横棒を選べるようにしておきます。

LightStick.vue
<template>
    <div class="stick" :class="[type, {light: light}]"  />
</template>

<script>
export default {
    props: {
        type: {
            typs: String,
            default: 'vertical'
        }
    },

    data() {
        return {
            light: false
        }
    },

    methods: {
        on() {
            this.light = true
        },

        off() {
            this.light = false
        }
    }
}
</script>

<style scoped>
.stick {
    background-color: rgba(200,255,200,0.2);
    border-radius: 10px;
}

.vertical {
    height: 50px;
    width: 10px;
}

.horizontal {
    height: 10px;
    width: 50px;
}

.light {
    background-color: yellowgreen;
}
</style>

NumberPanel

光る棒を組み合わせて数字の形を作ります。

NumberPanelDiscription.PNG

あとは数字に合わせて「光棒何号」を光らせるかを決めるだけです。
「1」なら「いけ!!3号!!6号!!」といった具合です。

NumberPanel.vue
<template>
    <div class="number-panel">
        <light-stick type="horizontal" class="stick stick1" ref="stick1" />
        <light-stick type="vertical"   class="stick stick2" ref="stick2" />
        <light-stick type="vertical"   class="stick stick3" ref="stick3" />
        <light-stick type="horizontal" class="stick stick4" ref="stick4" />
        <light-stick type="vertical"   class="stick stick5" ref="stick5" />
        <light-stick type="vertical"   class="stick stick6" ref="stick6" />
        <light-stick type="horizontal" class="stick stick7" ref="stick7" />
    </div>
</template>

<script>
import LightStick from "./LightStick"

export default {
    components: {
        LightStick
    },

    props: {
        number: 0
    }, 

    watch: {  
        number() {   //numberの変更とともに表示
            this.display()
        }
    },

    mounted() {   //初期表示設定
        this.display()
    },

    methods: {
        display() {
            switch(this.number) {
                case 0: 
                    this.zero()
                    break
                case 1:
                    this.one()
                    break
                case 2:
                    this.two()
                    break
                case 3:
                    this.three()
                    break
                case 4:
                    this.four()
                    break
                case 5:
                    this.five()
                    break
                case 6:
                    this.six()
                    break
                case 7:
                    this.seven()
                    break
                case 8:
                    this.eight()
                    break
                case 9:
                    this.nine()
                    break
            }
        },

        clear() {
            this.$refs.stick1.off()  //子コンポーネントのメソッド呼び出しにはref属性を使用
            this.$refs.stick2.off()
            this.$refs.stick3.off()
            this.$refs.stick4.off()
            this.$refs.stick5.off()
            this.$refs.stick6.off()
            this.$refs.stick7.off()
        },

        one() {
            this.clear()
            this.$refs.stick3.on()
            this.$refs.stick6.on()
        },

        two() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick3.on()
            this.$refs.stick4.on()
            this.$refs.stick5.on()
            this.$refs.stick7.on()
        },

        three() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick3.on()
            this.$refs.stick4.on()
            this.$refs.stick6.on()
            this.$refs.stick7.on()
        },

        four() {
            this.clear()
            this.$refs.stick2.on()
            this.$refs.stick3.on()
            this.$refs.stick4.on()
            this.$refs.stick6.on()
        },

        five() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick2.on()
            this.$refs.stick4.on()
            this.$refs.stick6.on()
            this.$refs.stick7.on()
        },

        six() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick2.on()
            this.$refs.stick4.on()
            this.$refs.stick5.on()
            this.$refs.stick6.on()
            this.$refs.stick7.on()
        },

        seven() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick3.on()
            this.$refs.stick6.on()
        },

        eight() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick2.on()
            this.$refs.stick3.on()
            this.$refs.stick4.on()
            this.$refs.stick5.on()
            this.$refs.stick6.on()
            this.$refs.stick7.on()
        },

        nine() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick2.on()
            this.$refs.stick3.on()
            this.$refs.stick4.on()
            this.$refs.stick6.on()
            this.$refs.stick7.on()
        },

        zero() {
            this.clear()
            this.$refs.stick1.on()
            this.$refs.stick2.on()
            this.$refs.stick3.on()
            this.$refs.stick5.on()
            this.$refs.stick6.on()
            this.$refs.stick7.on()
        }

    }
}
</script>

<style scoped>
.number-panel {
    background-color: #222;
    position: relative;
    height: 130px;
    width: 70px;
}

.stick {
    position: absolute;
}

.stick1 {
    top: 0;
    left: 10px;
}

.stick2 {
    top: 10px;
    left: 0;
}

.stick3 {
    top: 10px;
    left: 60px;
}

.stick4 {
    top: 60px;
    left: 10px;
}

.stick5 {
    top: 70px;
    left: 0;
}

.stick6 {
    top: 70px;
    left: 60px;
}

.stick7 {
    top: 120px;
    left: 10px;
}
</style>

Separation

ただの区切りです。ハイ。

Separation.vue
<template>
    <div class="colon">
        <div class="circle" />
        <div class="circle" />
    </div>
</template>

<style scoped>
.circle {
    background-color: yellowgreen;
    border-radius: 5px;
    width: 10px;
    height: 10px;
}

.colon {
    height: 130px;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
}
</style>

DigitalClock

NumberPanelとSeparationを並べて時計の形を作ります。

あとは時刻の各値をNumberPanelに割り当てればOKです。
時刻の取得については別途解説します。

DigitalClock.vue
<template>
    <div class="clock">
        <div class="display">
            <number-panel :number="hours2" />
            <number-panel :number="hours1" />
            <separation />
            <number-panel :number="minutes2" />
            <number-panel :number="minutes1" />
            <separation />
            <number-panel :number="seconds2" />
            <number-panel :number="seconds1" />
        </div>
    </div>
</template>

<script>
import NumberPanel from "./NumberPanel"
import Separation from "./Separation"
import moment from "moment"

export default {
    components: {
        NumberPanel,
        Separation
    },

    data() {
        return {
            time: undefined,
            intervalId: undefined
        }
    },

    methods: {
        setTime() {
            this.intervalId = setInterval(() => {
                this.time = new Date()
            }, 100)
        }
    },

    mounted() {
        this.setTime()
    },

    beforeDestroy() {
        clearInterval(this.intervalId)
    },

    computed: {
        hours1() {
            return moment(this.time).format("HH") % 10
        },

        hours2() {
            return Math.floor(moment(this.time).format("HH") / 10)
        },

        minutes1() {
            return moment(this.time).format("mm") % 10
        },

        minutes2() {
            return Math.floor(moment(this.time).format("mm") / 10)
        },

        seconds1() {
            return moment(this.time).format("ss") % 10
        },

        seconds2() {
            return Math.floor(moment(this.time).format("ss") / 10)
        }
    }
}
</script>

<style scoped>
.clock {
    background-color: #111;
    filter: drop-shadow(10px 10px 10px rgba(0,0,0,0.6));
    padding: 50px;
}

.display {
    background-color: #222;
    display: flex;
    justify-content: space-between;
    padding: 10px;
    width: 600px;
}    
</style>

setInterval

時計を実装するために一定間隔で時刻を取得する必要があります。
その時に使用するのがsetIntervalです。

data() {
    return {
        intervalId: undefined    //1. clearIntervalのためのIDを保持します
    }
},

methods: {
    do() {    //2. 一定間隔で処理を実行するためメソッドを用意します
        this.intervalId = setInterval(() => {  
            //処理内容
        }, 1000) //1秒間隔で処理
    }
},

mounted() {  //3. 上記で用意したメソッドをマウントのタイミングで呼び出します。
             //   これによりこのコンポーネントは一定間隔で処理を実行することになります。
    this.do()
},

beforeDestroy() {    //4. 使用後はしっかりとクリアする必要があります
    clearInterval(this.intervalId)
}

Moment.js

$npm install moment

javascriptで日付処理を容易にするためのライブラリです。
今回はフォーマットで使用しています。
これ以上はすみませんが割愛します。

vue-momentというのもあるみたいです。
詳しくは見ていません。ハイ。

おわりに

フロント学び始めたばかりだけど自由度が高くて楽しい!!でも難しい!!

今回のももっといい方法があるかもしれませんが、棒を光らせたい!!という思いでこんな感じになってしまいました。

次はもっといいものを作りたいですね。

13
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
18