はじめに
ブラウザにローカルのファイルシステム上のファイルをドラッグ&ドロップしたらそのファイルの内容をブラウザ上に表示する(より正確にはブラウザのテキストエリアに入力されている編集可能な文字列に対してファイルに記載されている文字列を追加する)ためのコードを書いてみることにしました。
最初の関門: バイナリファイルを排除する。
「ブラウザ上に表示する(より正確には以下略)」という要件があるため、表示をしてもあまり意味のなさそうなバイナリファイルがドラッグ&ドロップされた場合にはエラーとしてドロップさせないように実装するのが打倒と考えられます。
そこで、FileReader.readAsArrayBuffer()関数を使ってドラッグ&ドロップされたファイルの内容を読み込み、読み込んだファイルに書かれているデータ列にテキストファイルで使用される文字コードとして有効なデータ以外のデータを含むファイルをバイナリファイルとみなし、ドロップを拒否するコードを書くことにしました。
具体的にはVue.jsのメソッドとして以下のようなコードを書きました。
7-20行目でドロップできるファイルの数を1個に限定し、かつコードの組み込み先の都合によりファイルの末尾が”tex”で終わっているファイル以外のファイルをフィルタリングしています。
ドロップ可能と判定されたファイルについては、FileReaderのonloadイベントのイベントハンドラでアップロードされたファイルの中身にバイナリデータが含まれていないか確認し、バイナリデータが含まれていた場合には37行目でエラーメッセージを出力しています。
なお、バイナリデータが含まれているかどうかの判定用のコードは参考文献[1]に記載のコードをもとにして、Vue.js用のJavaScriptに組み込むための変更を行っています。
上記のコードを現在鋭意暇を見つけては開発中のmathletに組み込んで動作確認を行いました。
次の関門: もう少しモダンなコードにしたい。
前節のコード例ではonloadのイベントハンドラ中ではthis変数を使ってVueインスタンスにアクセスすることができないため、イベントハンドラの外側で別の変数(_this)にthisを代入し(40行目)、_thisをイベントハンドラの内部で参照するコードとしています(34行目の部分に”_this.メソッド名(引数)”の形式で記述します)。
コードの量が少ないのであまり気にならないかもしれませんが、後で見直したときに「この_thisって何のために存在するんだっけ?」と思って、再度確認し直してしまうことにより時間を無駄に使ってしまう可能性がありそうです。
そこで、もう少しモダンな書き方ができないものかと思い、「readAsArrayBuffer」でGoogle先生に訊いてみると、Mozillaのページ[2]がヒットしました。
そこには…
スポンサーリンク
と書かれていました。
Fileの親クラスであるBlobのメソッドであるBlob.arrayBuffer()がPromiseを返すのであれば、_thisのような「後で見直したときに用途や意図がわからなくなりがちな」変数は用意しなくてもよくなりそうです。
そこで、前節のコードを以下のように書き換えます。
Blob.arrayBuffer()はPromiseを返すので、onloadのイベントハンドラをPromiseチェーンで書き換えています。
_this及びFileReaderが消え、読みやすいモダンなコードになりました(自画自賛)。
適用例
前節のコードをmathletのテキストエリアに組み込んで動作確認を行います。
動作確認の結果は以下の通りになります。
意図した動作ができていることが確認できました。
まとめ
前節の動画をご覧いただくとご理解いただけると思いますが、ドラッグ&ドロップ時にファイルをドラッグしてテキストエリアにマウスのポインタが移動してきた際にドロップ可能であることを示すための処理はこの記事のコードには実装しておりません。
その点についてはご容赦願います。
この記事は以上です。