文件选择元素很容易成为网络上最丑陋的输入类型之一. 它们在每个浏览器中都以不同的方式实现,并且通常非常丑陋. 尽管存在一些解决方案,我们在这里将向您展示一种方法,使用标签和一些Vue.js魔法。
设置
如果您尚未设置一个项目,请使用 vue-cli的 webpack-simple 模板启动一个新的项目。
1$ npm install -g vue-cli
2$ vue init webpack-simple ./file-upload # Follow the prompts.
3$ cd ./file-upload
4$ npm install # or yarn
组件 Template & Styles
该组件的目的是简单地将隐藏的输入 type="file" 元素包装到标签中,并显示其中的其他东西。
1[label FileSelect.vue (template)]
2<template>
3 <!--
4 Everything is wrapped in a label, which acts as a clickable wrapper around a form element.
5 In this case, the file input.
6 -->
7 <label class="file-select">
8 <!-- We can't use a normal button element here, as it would become the target of the label. -->
9 <div class="select-button">
10 <!-- Display the filename if a file has been selected. -->
11 <span v-if="value">Selected File: {{value.name}}</span>
12 <span v-else>Select File</span>
13 </div>
14 <!-- Now, the file input that we hide. -->
15 <input type="file" @change="handleFileChange"/>
16 </label>
17</template>
18...
现在,一些漂亮的简单风格给它一个相当的按钮的外观。
1[label FileSelect.vue (styles)]
2...
3<style scoped>
4.file-select > .select-button {
5 padding: 1rem;
6
7 color: white;
8 background-color: #2EA169;
9
10 border-radius: .3rem;
11
12 text-align: center;
13 font-weight: bold;
14}
15
16/* Don't forget to hide the original file input! */
17.file-select > input[type="file"] {
18 display: none;
19}
20</style>
逻辑
文件是浏览器的一个非常特殊的类型,所以有几个特殊的规则,使他们有时有点棘手的工作。 (更多关于这里.)尽管如此,我们实际上可以得到一个非常简单的控制器。
1[label FileSelect.vue (script)]
2<script>
3export default {
4 props: {
5 // Using value here allows us to be v-model compatible.
6 value: File
7 },
8
9 methods: {
10 handleFileChange(e) {
11 // Whenever the file changes, emit the 'input' event with the file data.
12 this.$emit('input', e.target.files[0])
13 }
14 }
15}
16</script>
使用
现在,我们可以将我们的新组件导入我们的应用程序,并像任何其他组件一样使用它,并且完全支持v型号。
1[label App.vue]
2<template>
3 <div>
4 <p>My File Selector: <file-select v-model="file"></file-select></p>
5 <p v-if="file">{{file.name}}</p>
6 </div>
7</template>
8
9<script>
10import FileSelect from './FileSelect.vue'
11
12export default {
13 components: {
14 FileSelect
15 },
16
17 data() {
18 return {
19 file: null
20 }
21 }
22}
23</script>
现在你可以通过组件对用户选择的文件进行完全反动访问,然后可以将其包装到上传组件中,或者通过FileReader API(https://developer.mozilla.org/en-US/docs/Web/API/FileReader)以某种方式处理数据。
完整组件代码
对于那些想要一次的一切的人来说,在这里你去!正如我所承诺的那样,只有41行。
1[label FileSelect.vue]
2<template>
3 <label class="file-select">
4 <div class="select-button">
5 <span v-if="value">Selected File: {{value.name}}</span>
6 <span v-else>Select File</span>
7 </div>
8 <input type="file" @change="handleFileChange"/>
9 </label>
10</template>
11
12<script>
13export default {
14 props: {
15 value: File
16 },
17
18 methods: {
19 handleFileChange(e) {
20 this.$emit('input', e.target.files[0])
21 }
22 }
23}
24</script>
25
26<style scoped>
27.file-select > .select-button {
28 padding: 1rem;
29
30 color: white;
31 background-color: #2EA169;
32
33 border-radius: .3rem;
34
35 text-align: center;
36 font-weight: bold;
37}
38
39.file-select > input[type="file"] {
40 display: none;
41}
42</style>