Vue.jsで動画サイトによくある動画のプログレスバーを作る

# はじめに
YouTubeなどの動画サイトによくある再生時間のプログレスバー（サムネイル画像の下に表示される赤色のバーなど）を作ってみます。


# TL;DRな方へ

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271414/12f766ae-a6a5-a717-9060-4cb652e9736b.png)
サムネイル画像の下に赤色のバーとグレーの背景が表示されています。
現在の再生時間が500秒で全体が1000秒で設定しているので、赤色のバーがちょうど真ん中の位置まで達していることがわかります。

## コード
```vuejs:movie.vue
<template>
  <div class="movie">
    <!-- サムネイル画像 -->
    <v-img class="movie__thumbnail" src="https://picsum.photos/id/11/500/300" :aspect-ratio="16/9">
      <!-- プログレスバーの背景 -->
      <div class="movie__thumbnail__progress">
        <!-- プログレスバー -->
        <div class="movie__thumbnail__progress__bar" :style="'width: ' + durationPercentage" />
      </div>
    </v-img>
  </div>
</template>

<script>
export default {
  computed: {
    /**
     * @return {Number} 動画の尺（秒）
     * @todo 動的に取得しましょう
     */
    duration () {
      return 1000
    },
    /**
     * @return {Number} 現在の再生時間（秒）
     * @todo 動的に取得しましょう
     */
    currentTime () {
      return 500
    },
    /**
     * @return {String} 動画の尺に対する現在の再生時間のパーセンテージ
     */
    durationPercentage () {
      return String(this.currentTime / this.duration * 100) + '%'
    }
  }
}
</script>

<style lang="scss" scoped>
.movie {
  &__thumbnail {
    position: relative;
    width: 480px;
    height: 270px;
    background-color: #808080;
    &__progress {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 4px;
      background-color: #808080;
      &__bar {
        height: 100%;
        background-color: #dc143c;
      }
    }
  }
}
</style>

```

# 詳細
## HTML
```vuejs:movie.vue(HTML)
<template>
  <div class="movie">
    <!-- サムネイル画像 -->
    <v-img class="movie__thumbnail" src="https://picsum.photos/id/11/500/300" :aspect-ratio="16/9">
      <!-- プログレスバーの背景 -->
      <div class="movie__thumbnail__progress">
        <!-- プログレスバー -->
        <div class="movie__thumbnail__progress__bar" :style="'width: ' + durationPercentage" />
      </div>
    </v-img>
  </div>
</template>
...
```
全体に大きな```div```があって、その中にサムネイル画像、そしてプログレスバーの背景色がネストされて、更にプログレスバー（現在の再生時間）がネストされています。
```movie__thumbnail__progress__bar```は幅が可変にしたいので、v-bindでstyleを指定することで実現しています。

## Script
```vuejs:movie.vue(Script)
...
<script>
export default {
  computed: {
    /**
     * @return {Number} 動画の尺（秒）
     * @todo 動的に取得しましょう
     */
    duration () {
      return 1000
    },
    /**
     * @return {Number} 現在の再生時間（秒）
     * @todo 動的に取得しましょう
     */
    currentTime () {
      return 500
    },
    /**
     * @return {String} 動画の尺に対する現在の再生時間のパーセンテージ
     */
    durationPercentage () {
      return String(this.currentTime / this.duration * 100) + '%'
    }
  }
}
</script>
...
```
Script部分は大したことはしていません。
### duration(), currentTime()
恐らく、サーバーにストアされた値を動的に取得する方式になると思います。
今は決め打ちで定数を返すようにしています。

### durationPercentage()
動画全体の尺に対する再生時間の割合を計算しています。```style```は```String```で記述する必要があるので、計算結果を```String```にして%を付与して返しています。

## CSS
```vuejs:movie.vue(Script)
...
<style lang="scss" scoped>
.movie {
  &__thumbnail {
    position: relative;
    width: 480px;
    height: 270px;
    background-color: #808080;
    &__progress {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 4px;
      background-color: #808080;
      &__bar {
        height: 100%;
        background-color: #dc143c;
      }
    }
  }
}
</style>
```
### __thumbnail
プログレスバー全体を画像の上にかかるように表示したいので、```position```に```relative```が指定されています。また、サムネイル画像が指定されていない場合はグレーの背景が表示されるように、```background```を指定しています。
### __progress
プログレスバーが画像全体に対する指定された位置に置かれるように```position```を```absolute```にしています。
画像の真下かつ左隅に合わせて置きたいので```bottom```と```left```を0にしています。
色はお好みで選びましょう。
### __bar
ここが現在の再生時間に合わせて```width```が変わります。
高さは```__progress```と同じにしたいので、100%を指定しています。
こちらも色はお好みで指定しましょう。

以上で完成です。
動画だけじゃなくフォームやアンケートの入力状況などにも応用できると思います。
ぜひ活用してみてください。