ファイル選択要素は、Web上で最も醜い入力タイプの1つです。 それらはブラウザごとに異なって実装されており、一般的に信じられないほど醜いです。 ただし、いくつかの回避策があります。ここでは、ラベルとVue.jsの魔法を使用した1つのアプローチを紹介します。
設定
プロジェクトをまだ設定していない場合は、vue-cliのwebpack-simpleテンプレートを使用して新しいプロジェクトを開始します。
$ npm install -g vue-cli
$ vue init webpack-simple ./file-upload # Follow the prompts.
$ cd ./file-upload
$ npm install # or yarn
コンポーネントテンプレートとスタイル
このコンポーネントの目的は、非表示の input type =“ file” 要素をラベルでラップし、その中に何か他のものを表示することです。 この手法は単純ですが、驚くほど効果的です。
FileSelect.vue(テンプレート)
<template>
<!--
Everything is wrapped in a label, which acts as a clickable wrapper around a form element.
In this case, the file input.
-->
<label class="file-select">
<!-- We can't use a normal button element here, as it would become the target of the label. -->
<div class="select-button">
<!-- Display the filename if a file has been selected. -->
<span v-if="value">Selected File: {{value.name}}</span>
<span v-else>Select File</span>
</div>
<!-- Now, the file input that we hide. -->
<input type="file" @change="handleFileChange"/>
</label>
</template>
...
そして今、それにかなりボタンのような外観を与えるためのいくつかの素敵なシンプルなスタイル。
FileSelect.vue(スタイル)
...
<style scoped>
.file-select > .select-button {
padding: 1rem;
color: white;
background-color: #2EA169;
border-radius: .3rem;
text-align: center;
font-weight: bold;
}
/* Don't forget to hide the original file input! */
.file-select > input[type="file"] {
display: none;
}
</style>
ロジック
ファイルはブラウザにとって非常に特殊なタイプであるため、ファイルを操作するのが少し難しい場合がある特別なルールがいくつかあります。 (詳細はこちら。)それにもかかわらず、実際には非常に単純なコントローラーで問題を解決できます。 他のカスタム入力要素と同じくらい短いです。
FileSelect.vue(スクリプト)
<script>
export default {
props: {
// Using value here allows us to be v-model compatible.
value: File
},
methods: {
handleFileChange(e) {
// Whenever the file changes, emit the 'input' event with the file data.
this.$emit('input', e.target.files[0])
}
}
}
</script>
使用法
これで、新しいコンポーネントをアプリにインポートして、v-modelを完全にサポートする他のコンポーネントと同じように使用できるようになりました。
App.vue
<template>
<div>
<p>My File Selector: <file-select v-model="file"></file-select></p>
<p v-if="file">{{file.name}}</p>
</div>
</template>
<script>
import FileSelect from './FileSelect.vue'
export default {
components: {
FileSelect
},
data() {
return {
file: null
}
}
}
</script>
これで、ユーザーがコンポーネントを介して選択したファイルに完全にリアクティブにアクセスできます。 次に、それをアップロードコンポーネントでラップするか、 FileReaderAPIを使用して何らかの方法でデータを処理できます。 楽しむ!
完全なコンポーネントコード
一度にすべてが欲しい人のために、ここに行きます! 約束通り、41行しかありません。 🙂
FileSelect.vue
<template>
<label class="file-select">
<div class="select-button">
<span v-if="value">Selected File: {{value.name}}</span>
<span v-else>Select File</span>
</div>
<input type="file" @change="handleFileChange"/>
</label>
</template>
<script>
export default {
props: {
value: File
},
methods: {
handleFileChange(e) {
this.$emit('input', e.target.files[0])
}
}
}
</script>
<style scoped>
.file-select > .select-button {
padding: 1rem;
color: white;
background-color: #2EA169;
border-radius: .3rem;
text-align: center;
font-weight: bold;
}
.file-select > input[type="file"] {
display: none;
}
</style>