webページではファイルの送信のためにフォームの type=”file” の input タグを使うことが多いです。見た目の上では使っておらずとも入力欄では内部的にこれを持っていることが多いです。
<input type=”file”> – HTML: HyperText Markup Language | MDN
この input[type=”file”] にファイルをセットした時、どのファイルがセットされているのか後から確認したいという要望が少なからずあります。ブラウザの素の機能でセットしたファイルの名前までは表示されるのですが、中身はわかりません。プレビューを表示できればよいのですが、システムの目的によっては画像やテキストファイルといったプレビューしやすいファイル以外も扱う時があります。限定的ならばなんやかんや何とかなりやすいのですが、なんでもアップロードできる場合は問題です。多様なファイル全てのランタイムをブラウザで実行するプログラムに含めるのは現実的ではありません。妥協案として使えるセットしたファイルをその場でダウンロードできる方法を紹介します。紹介する方法の特徴的な点はサーバーへのアップロードを行わない点にあります。この点により、高速でセキュアな簡易なプレビューを実現できます。
実際のデモとコードが次です。
<div class="App"> <input type="file" id="send-file" /> <a id="for-preview"></a> </div>
// ファイルが変更された時に実行される関数
const handleChange = (e) => {
const reader = new FileReader();
// FileReader からBase64形式の URL として使えるファイルの中身を取得
// a タグの href にすることでファイルのダウンロードを実現する
const previewEl = document.getElementById("for-preview");
// @see https://developer.mozilla.org/ja/docs/Web/API/FileReader
reader.addEventListener("load", () => (previewEl.href = reader.result));
// ファイルを FileReader に渡す。
const file = e.currentTarget.files[0];
if (file) {
/ ダウンロードするファイルの名前とダウンロードリンクに表示される文字列をセットされたファイルの名前にする
previewEl.download = file.name;
previewEl.innerText = file.name;
// @see https://developer.mozilla.org/ja/docs/Web/API/FileReader/readAsDataURL
reader.readAsDataURL(file);
}
};
document.getElementById("send-file").addEventListener("change", handleChange);
import "./styles.css";
import React from "react";
// React 版です
export default function App() {
// fileの中身と名前を保持
const [uri, setUri] = React.useState("");
const [fileName, setFileName] = React.useState("");
// ファイル変更あったら↑にセット
const handleChange = (e) => {
const reader = new FileReader();
// @see https://developer.mozilla.org/ja/docs/Web/API/FileReader
reader.addEventListener("load", () => setUri(reader.result));
const file = e.currentTarget.files[0];
if (file) {
setFileName(file.name);
// @see https://developer.mozilla.org/ja/docs/Web/API/FileReader/readAsDataURL
reader.readAsDataURL(file);
}
};
return (
<div className="App">
<input type="file" onChange={handleChange} />
<a href={uri} download={fileName}>
{fileName}
</a>
</div>
);
}
セットされたファイルに変更があったら、それを FileReader.readAsDateURL で中身を読み取り、Base64 として a 要素の href にセットしています。これの a 要素を img 要素に、 href を src に変えればそれでもう画像のプレビューと同じです。
FileReader.readAsDataURL() – Web API | MDN
特別ライブラリを用いずともブラウザ標準の機能で比較的シンプルにまとまります。