0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SNSによくある経過時間を表示するコンポーネントをvueで実装してみた

Last updated at Posted at 2019-01-31

TwitterやFacebookなどで見かける「投稿してから○分経過」のようなコンポーネントを作成しました。
lastTime.gif

setInterval() を使用し、vue.jsとTypescriptで実装しています。表示する時間の単位によってインターバルの間隔を変更しています。ほぼTypescriptなので、他のjavascriptフレームワークにも簡単に移植出来ると思います。

全体像

src/components/LastTime.vue
<template>
  <div>{{ lastTime }}</div>
</template>

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'

enum IntervalTime {
  SEC = 1000,
  MIN = 60 * IntervalTime.SEC,
  HOUR = 60 * IntervalTime.MIN,
  DAY = 24 * IntervalTime.HOUR,
  WEEK = 7 * IntervalTime.DAY,
  YEAR = 52 * IntervalTime.WEEK,
}

enum TimeUnit {
  SEC = 'sec',
  MIN = 'min',
  HOUR = 'hour',
  DAY = 'day',
  WEEK = 'week',
  YEAR = 'year',
}

@Component
export default class LastTime extends Vue {
  @Prop({ default: () => 0 }) baseTime!: number
  duration: number = 0
  intervalId: number = 0
  intervalTime: IntervalTime = IntervalTime.SEC
  timeUnit: TimeUnit = TimeUnit.SEC

  created() {
    const currentTime = new Date().getTime()
    this.duration = currentTime - this.baseTime
    this.intervalId = setInterval(() => {
      this.timer()
    }, this.intervalTime)
  }

  timer() {
    const currentTime = new Date().getTime()
    this.duration = currentTime - this.baseTime
    if (this.duration > IntervalTime.YEAR) {
      this.restartInterval(IntervalTime.YEAR, TimeUnit.YEAR)
    } else if (this.duration > IntervalTime.WEEK && this.intervalTime <= IntervalTime.DAY) {
      this.restartInterval(IntervalTime.WEEK, TimeUnit.WEEK)
    } else if (this.duration > IntervalTime.DAY && this.intervalTime <= IntervalTime.HOUR) {
      this.restartInterval(IntervalTime.DAY, TimeUnit.DAY)
    } else if (this.duration > IntervalTime.HOUR && this.intervalTime <= IntervalTime.MIN) {
      this.restartInterval(IntervalTime.HOUR, TimeUnit.HOUR)
    } else if (this.duration > IntervalTime.MIN && this.intervalTime <= IntervalTime.SEC) {
      this.restartInterval(IntervalTime.MIN, TimeUnit.MIN)
    }
  }

  restartInterval(intervalTime: IntervalTime, timeUnit: TimeUnit) {
    clearInterval(this.intervalId)
    this.intervalTime = intervalTime
    this.timeUnit = timeUnit
    this.intervalId = setInterval(() => {
      this.timer()
    }, this.intervalTime)
  }

  get lastTime(): string {
    let divide: IntervalTime = IntervalTime.SEC
    if (this.duration < IntervalTime.MIN) {
    } else if (this.duration < IntervalTime.HOUR) {
      divide = IntervalTime.MIN
    } else if (this.duration < IntervalTime.DAY) {
      divide = IntervalTime.HOUR
    } else if (this.duration < IntervalTime.WEEK) {
      divide = IntervalTime.DAY
    } else if (this.duration < IntervalTime.YEAR) {
      divide = IntervalTime.WEEK
    } else {
      divide = IntervalTime.YEAR
    }
    return Math.floor(this.duration / divide) + ' ' + this.timeUnit
  }
}
</script>

<style lang="scss" scoped></style>

設計のキモ

enum IntervalTime

enum IntervalTime {
  SEC = 1000,
  MIN = 60 * IntervalTime.SEC,
  HOUR = 60 * IntervalTime.MIN,
  DAY = 24 * IntervalTime.HOUR,
  WEEK = 7 * IntervalTime.DAY,
  YEAR = 52 * IntervalTime.WEEK,
}

時間の処理を書く時によく書きがちな60 * 60 * 1000のような計算を、enumを使って定義しています。どのような計算をしているか一目で分かると思います。このように書くことで「掛ける値の桁が足りてなかった!」などといったちょっとしたミスを減らすことができます。

restartInterval()

restartInterval(intervalTime: IntervalTime, timeUnit: TimeUnit) {
  clearInterval(this.intervalObj)
  this.intervalTime = intervalTime
  this.timeUnit = timeUnit
  this.intervalObj = setInterval(() => {
    this.timer()
  }, this.intervalTime)
}

分表記や時間表記の時に1000msで再描画しても無駄なので、経過時間によって、setInterval()の間隔を長くします。

get lastTime()

get lastTime(): string {
  let divide: IntervalTime = IntervalTime.SEC
  if (this.duration < IntervalTime.MIN) {
  } else if (this.duration < IntervalTime.HOUR) {
    divide = IntervalTime.MIN
  } else if (this.duration < IntervalTime.DAY) {
    divide = IntervalTime.HOUR
  } else if (this.duration < IntervalTime.WEEK) {
    divide = IntervalTime.DAY
  } else if (this.duration < IntervalTime.YEAR) {
    divide = IntervalTime.WEEK
  } else {
    divide = IntervalTime.YEAR
  }
  return Math.floor(this.duration / divide) + ' ' + this.timeUnit
}

computedで時間の単位とともに経過時間を出力します。

その他

細かいところはもっと改良できそうな気がするのでお気づきの点があればプルリクもしくはコメント下さい!

:octocat: MssKnd/LastTime

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?