画像アップロードする時に、以下のように display: none
をつかってブラウザ本来の input[type=file]
をみえないようにした上で独自レイアウトのボタンで画像アップロードするような実装を時々みかけます。
<label for="hoge">画像アップロード</label>
<input id="hoge" type="file" style="display: none">
で、 addEventListener
でファイル変更検知を行ったりと。
けれど、上記のようにするとマークアップがある程度拘束されてしまいます。やりたいことはボタンをクリックしたら画像をアップロードしてBase64を手にいれるとかそういう話なので、クリックイベントを仕込んで以下のコードを実行すればOKです。
<div style="width: 0; height: 0; overflow: hidden;">
<input id="browserPhotoUploader" type="file" accept="image/*" />
</div>
public getPictureFromBrowser() {
/*
* input[type=file] を組み立て
*/
const inputFile: HTMLElement = document.querySelector('input#browserPhotoUploader');
return new Promise(resolve => {
/*
* input[type=file] の変更(change)を検知したら、ファイルをアップロードしてresolveする
*/
inputFile.addEventListener(
'change',
(e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (fileInput => {
/*
* アップロードされるファイルが画像かを簡易判定
*/
if (file.type.indexOf('image') < 0) {
reject(null);
}
return (event) => {
resolve(event.target.result);
};
})(file);
reader.readAsDataURL(file);
},
false,
);
/*
* input[type=file] をクリック
* イベントリスナーよりあとに実行されるように
*/
inputFile.click();
});
}
このコードだったらHTML側は
<button (click)="getPictureFromBrowser()">画像アップロード</button>
だけで済みますね。 display:none
せずにすむのでシンプル!
それでは、また。
おまけ: TypeScript版
any
使ってるのちょっと何ですが・・・。
public getPictureFromBrowser(): Promise<string> {
const inputFile: HTMLElement = document.querySelector('input#browserPhotoUploader');
return new Promise(resolve => {
inputFile.addEventListener(
'change',
(e: any) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (fileInput => {
if (file.type.indexOf('image') < 0) {
reject(null);
}
return (event) => {
resolve(event.target.result);
};
})(file);
reader.readAsDataURL(file);
},
false,
);
inputFile.click();
});
}