ウェブフロント
- angular
- corewebvitals
- editorconfig
- gatsby
- hls
- html
- javascript
querySelectorAllで取得した要素は配列ではないらしい
JavaScript 配列内のオブジェクトの更新ってどうする?
デバッグ関数とかnullチェック関数をutil/index.tsにおいとけば楽なことに今頃気づいた。
ブラウザからジャイロセンサーを使ってみる
JS 画像のアップロード、プレビュー機能を実装
「数値から各桁の値を取り出す処理」って言われたら数学的な処理が一番に思い浮かぶけど、JSならそんなことなかった。
Callback時代の関数をPromise化する
個人的実装されてほしいECMA Script Proposal
JavaScriptのprototypeを使う
音声をなみなみさせる
AudioWorkletとAudioWorkletProcessorを使って音声のビジュアライゼーション
- next
- nuxt
- playwright
- prettier
- react
- reactnative
- tensorflowjs
- tools
- typescript
- wasm
- websocket
- ポエム
- 開発環境
サーバー
その他
JS 画像のアップロード、プレビュー機能を実装
HTML部分
<label for="image">アップロードする画像を選択してください。</label>
<input type="file" id="image" accept="image/*" name="image" multiple>
<div class="container"></div>
inputのtypeをfileにするとファイルをアップロードできるようになります。
そしてacceptでアップロードできるファイルを絞っています。今回は画像のみにしたいので
multiple属性は複数アップロードできるようにするためです。
そしてacceptでアップロードできるファイルを絞っています。今回は画像のみにしたいので
image/*
にしました。 jpg, png,
gifとかをアップロードできます。multiple属性は複数アップロードできるようにするためです。
containerの中に画像のプレビューをしていきます。
単純な実装
1枚の画像のみの場合は、こんな感じでできます。
element.addEventListener("input", (event) => {
const target = event.target;
const files = target.files;
const file = files[0];
const reader = new FileReader();
reader.onload = () => {
const img = new Image();
img.src = reader.result;
container.appendChild(img);
};
reader.readAsDataURL(file);
});
filesのなかにアップロードした画像があります。
FileReaderは画像をプレビューするためにDataURLとして読み取ってくれます。(非同期)
FileReader.onloadで読み取りが終わったら画像を表示させてます。
FileReaderは画像をプレビューするためにDataURLとして読み取ってくれます。(非同期)
FileReader.onloadで読み取りが終わったら画像を表示させてます。
この実装でも良いんですけどちょっと単調なので、
- FileReaderで読み取るところを関数化したい
- 複数枚に対応させたい
です。
なのでもう少しいじっていきます.
Readerを関数化
こちらの通りです
参考
https://blog.shovonhasan.com/using-promises-with-filereader/
const readFileAsDataURL = (file) => {
const reader = new FileReader();
return new Promise((resolve, reject) => {
reader.onerror = () => {
reader.abort();
reject(new DOMException("Problem parsing input file."));
};
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(file);
});
};
Promiseにすることで関数化とawaitが使えるようになってとても嬉しいですね。
エラーが起きたときは読み取りを中断してreject, 読み取りが完了したら結果をresolveしています。
エラーが起きたときは読み取りを中断してreject, 読み取りが完了したら結果をresolveしています。
複数枚アップロードとエラーの対処など
fileListは配列のように見せかけてオブジェクトだったんですよねぇ。。
なのでArray.fromメソッドでくるくるしながらさっきの関数に通してプロミスの配列を作っていきます。
そしてPromise.allで一気に実行!
もしrejectされてるやつがあったらエラー起きちゃうのでcatchでの補足とfilterでエラーが起きたやつを取り除いています。
最後にプレビューしていきます。
なのでArray.fromメソッドでくるくるしながらさっきの関数に通してプロミスの配列を作っていきます。
そしてPromise.allで一気に実行!
もしrejectされてるやつがあったらエラー起きちゃうのでcatchでの補足とfilterでエラーが起きたやつを取り除いています。
最後にプレビューしていきます。
element.addEventListener("input", async (event) => {
const target = event.target;
const files = target.files;
const arrPromise = Array.from(
files,
(file) => readFileAsDataURL(file).catch((e) => e),
);
const results = await Promise.all(arrPromise);
// Errorを弾く
const validResults = results.filter((result) => !(result instanceof Error));
for (const result of validResults) {
const img = new Image();
img.src = result;
container.appendChild(img);
}
});
コード全体
<main>
<style>
.container {
display: flex;
flex-wrap: wrap;
}
</style>
<label for="image">アップロードする画像を選択してください。</label>
<input type="file" id="image" accept="image/*" name="image" multiple>
<div class="container"></div>
</main>
<script>
const element = document.querySelector('#image')
const container = document.querySelector('.container')
const readFileAsDataURL = (file) => {
const reader = new FileReader()
return new Promise((resolve, reject) => {
reader.onerror = () => {
reader.abort()
reject(new DOMException('Problem parsing input file.'))
}
reader.onload = () => {
resolve(reader.result)
}
reader.readAsDataURL(file)
})
}
element.addEventListener('input', async (event) => {
const target = event.target
const files = target.files
const arrPromise = Array.from(files, file => readFileAsDataURL(file).catch(e => e))
const results = await Promise.all(arrPromise)
// Errorを弾く
const validResults = results.filter(result => !(result instanceof Error))
for (const result of validResults) {
const img = new Image()
img.src = result
container.appendChild(img)
}
})
</script>
実行結果
formDataでアップロード
こんな感じ
const form = new FormData()
form.append('name', name)
images.forEach(image => {
if (image.file) form.append(image.key, image.file)
})
base64でアップロード
先頭部分の不要な文字列を削除する
fileData = v.replace(/^data:\w+\/\w+;base64,/, '')
TypeScriptでかくなら
private readFileAsDataURL (file: Blob): Promise<string | ArrayBuffer> {
const reader = new FileReader()
return new Promise((resolve, reject) => {
reader.onerror = () => {
reader.abort()
reject(new DOMException('Problem parsing input file.'))
}
reader.onload = () => {
resolve(reader.result)
}
reader.readAsDataURL(file)
})
}
Thanks you for reading.