javascript - 在 VueJS 应用程序中构建输入表单类型文件
问题描述
我正在尝试在 VueJS 中构建一个带有文件类型输入字段的组件。这是我的组件代码:
<template>
<div class="flex-col justify-start w-full">
<div class="mt-2 block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">{{ label }}</div>
<input
class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
:class="errorDisplay ? 'border-red-500 focus:bg-white focus:border-red-500': ''"
type="file"
:value="value" @input="emitEvent($event)"
ref="input_file"
>
<span v-if="hint" class="text-xs text-gray-400 font-medium">{{ hint }}</span>
<span v-if="errorDisplay" class="text-xs text-pink-600 font-medium">{{ errorDisplay }}</span>
</div>
</template>
<script>
export default {
name: "InputFile",
props: {
label: String,
hint: {
type: String,
default: () => ''
},
error: {
type: Array,
default: () => []
},
placeholder: String,
value: Object,
},
methods: {
emitEvent(event) {
var reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = () => {
const docs = {
name: event.target.files[0].name,
size: event.target.files[0].size,
lastModifiedDate: event.target.files[0].lastModifiedDate,
base64: reader.result
};
console.log(docs);
this.$emit('input', docs)
};
}
},
computed: {
errorDisplay() {
if(this.error.length)
return this.error.join(', ');
else
return '';
}
}
}
</script>
我正在调用我的组件,如下所示:
<template>
<div class="flex items-center justify-start">
<div class="w-1/2 m-2 rounded-lg shadow-lg border b-gray-400 rounded flex flex-col justify-start items-start p-6 bg-white">
<div class="border-b -m-2 mb-3 px-6 py-2 flex-none w-full justify-start text-gray-700 font-semibold"> Base Controls </div>
<input-file
label="Upload file"
v-model="upload_file"
:error="errors['upload_file']"
>
</input-file>
<div class="mt-4 text-center">
<button @click="submit()" class="inline-block px-4 py-2 rounded-lg shadow-md bg-teal-500 hover:bg-teal-400 focus:outline-none focus:shadow-outline text-white text-sm tracking-wider font-semibold">Submit</button>
</div>
</div>
</div>
</template>
<script>
import InputFile from "../Elements/Forms/Inputs/File";
export default {
name: "Forms",
components: {
InputFile,
},
data() {
return {
upload_file: '',
errors: {},
}
},
methods: {
submit() {
//Submit code...
}
}
}
</script>
但我总是收到一个错误:
nextTick 中的错误:“InvalidStateError:无法在 'HTMLInputElement' 上设置 'value' 属性:此输入元素接受文件名,该文件名只能以编程方式设置为空字符串。”
我可以看到我的事件正在发出并upload_file
设置了所需的值。为了克服这一点,我提出upload_file
了反对意见,但这会导致错误,并且该组件也未显示。我怎样才能解决这个问题?
解决方案
我相信问题出在试图分配给元素的“值”属性(通过将其绑定到 prop.value)
在处理文件类型元素时,不能像处理其他类型一样写入 value 属性。
在自定义组件的模板中,删除绑定,:value="value"
并在其脚本中:
- 删除道具
value: Object
,或者, - 如果您需要为 v-model 兼容性分配 value 属性,请将其分配给 File。例如:
value: File
注意:这会起作用,但是当在没有提供文件的情况下调用组件时,你会收到一个 Vue 警告:'type check failed' for an invalid prop。
IE...
<template>
<div class="flex-col justify-start w-full">
<div class="mt-2 block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2">{{ label }}</div>
<input
class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
:class="errorDisplay ? 'border-red-500 focus:bg-white focus:border-red-500': ''"
type="file"
@input="emitEvent($event)"
ref="input_file"
>
<span v-if="hint" class="text-xs text-gray-400 font-medium">{{ hint }}</span>
<span v-if="errorDisplay" class="text-xs text-pink-600 font-medium">{{ errorDisplay }}</span>
</div>
</template>
<script>
export default {
name: "InputFile",
props: {
label: String,
hint: {
type: String,
default: () => ''
},
error: {
type: Array,
default: () => []
},
placeholder: String,
value: File,
},
methods: {
emitEvent(event) {
var reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = () => {
const docs = {
name: event.target.files[0].name,
size: event.target.files[0].size,
lastModifiedDate: event.target.files[0].lastModifiedDate,
base64: reader.result
};
console.log(docs);
this.$emit('input', docs)
};
}
},
computed: {
errorDisplay() {
if(this.error.length)
return this.error.join(', ');
else
return '';
}
}
}
</script>
应该可以。
推荐阅读
- visual-studio-code - 如何在 VSCode SSH TARGETS 中为服务器设置多个文件夹?
- python - Values from .txt become null
- python - create one dict from list of dicts in DataFrame
- java - I can*t run Spring Boot application because of "java.lang.UnsupportedClassVersionError: Preview features are not enabled for AAA.class"
- javascript - Laravel AJAX 响应加载错误的路由/窗口
- xslt - 获取每个特定子节点的父节点值
- fortran - cgeev sovle Non Hermitan 矩阵不正确
- django - Django登录 - 不要去注册新用户
- r - 组合学:在不重复元素的情况下随机化,我是否试图做一些不可能的事情?
- ionic-framework - 这个时间/日期时间的类型是什么?