入力フォームで選択した動画を送信前に表示する

はじめに

実務にて、ライブラリやフレームワークを利用しないで、入力フォームで選択された動画を送信前に表示してほしいという小仕事の依頼があり、それを解決した情報になります。ソースコードをコピペ(コピー&ペースト)するだけで簡単に流用ができます。定数の値、デザインに関しましては、適宜修正をなさってください。

ソースコード

<span id="error" class="error"></span>
<form>
  <label for="inputVideo">
    動画を選択する
    <input type="file" id="inputVideo" accept="video/*">
  </label>
</form>
<hr>
<video id="outputVideo"/>

<script>
const MAX_FILES = 1
const MAX_FILE_SIZE = 400
const MAX_FILE_DURATION = 60
const MB = 1024 ** 2
const createVideo = document.createElement('video')

inputVideo.addEventListener('change', e => {
  try {
    let file = e.target.files
    if (file.length < MAX_FILES) throw new Error('動画を選択してください。')
    if ((file[0].size / MB) >= MAX_FILE_SIZE) throw new Error(MAX_FILE_SIZE + ' メガバイト以下の動画を選択してください。')
    let src = window.URL.createObjectURL(file[0])
    createVideo.src = src
    createVideo.autoplay = true
    createVideo.addEventListener('loadeddata', () => {
      if (createVideo.duration <= MAX_FILE_DURATION) {
        outputVideo.src = src
        outputVideo.controls = true
        if (/iP(hone|(o|a)d)/.test(navigator.userAgent)) outputVideo.autoplay = true
        error.textContent = ''
      } else error.textContent = MAX_FILE_DURATION + ' 秒以下の動画を選択してください。'
    })
  } catch (e) {
    error.textContent = e.message
  }
})
</script>

検証環境

解説

input 要素の change イベント発生後、addEventListener() メソッドで処理が走る仕掛けを作ります。

<input type="file" id="inputFilesId" multiple accept="image/png, image/jpeg">
inputFilesId.addEventListener('change', e => {
  // 処理
})

例外処理文 を記述します。

<span id="error" class="error"></span>
try {
  // 処理
} catch (e) {
  error.textContent = e.message
}

定数 を定義、選択ファイルの数と容量を検証します。

const MAX_FILES = 1
const MAX_FILE_SIZE = 400
const MB = 1024 ** 2
let file = e.target.files
if (file.length < MAX_FILES) throw new Error('動画を選択してください。')
if ((file[0].size / MB) >= MAX_FILE_SIZE) throw new Error(MAX_FILE_SIZE + ' メガバイト以下の動画を選択してください。')

video 要素を document.createElement() メソッドで生成します。

const createVideo = document.createElement('video')

URL.createObjectURL() 静的メソッドでオブジェクト URL を生成し、video 要素の src 属性に設定します。

let src = window.URL.createObjectURL(file[0])
createVideo.src = src

video 要素に autoplay 属性を追加します。iOS の Safari で autoplay 属性がないと loadeddata イベントが発生しない挙動をしていたので、その対処法です。

createVideo.autoplay = true

addEventListener() メソッドを利用して、loadeddata イベント発生後に処理が走る仕掛けを作ります。

createVideo.addEventListener('loadeddata', () => {
  // 処理
})

duration プロパティでメディアの長さ(秒)を取得して 定数 と比較します。

const MAX_FILE_DURATION = 60
if (createVideo.duration <= MAX_FILE_DURATION) {
  // 処理
} else error.textContent = MAX_FILE_DURATION + ' 秒以下の動画を選択してください。'

出力する video 要素の src 属性にオブジェクト URL を設定します。

<video id="outputVideo"/>
outputVideo.src = src

必要に応じて controls 属性を追加します。

outputVideo.controls = true

iPhone、iPod、iPad の場合、autoplay 属性の追加をします。iOS の Safari は autoplay 属性がない場合、動画のサムネイルが表示されないという挙動をしていたので、その対処法になります。

if (/iP(hone|(o|a)d)/.test(navigator.userAgent)) outputVideo.autoplay = true

正常に処理ができた場合、エラーメッセージを空にします。

error.textContent = ''

以上です。

おわりに

モバイルデバイスの実機のみ発生する不具合があったので、動画を扱う際は注意です。

参考