javascript - 在 VueJS 应用程序中构建输入表单类型文件

标签 javascript vue.js

我正在尝试在 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>

但我总是收到错误:

Error in nextTick: "InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string."

我可以看到我的事件正在发出,并且 upload_file 设置了所需的值。为了克服这个问题,我提出了 upload_file 来反对,但这会导致错误,并且组件也不会显示。我怎样才能解决这个问题?

最佳答案

我认为问题来自于尝试分配给元素的“value”属性(通过将其绑定(bind)到 prop.value)

当您处理文件类型元素时,您can't write与其他类型一样,添加到 value 属性。

在自定义组件的模板中,删除绑定(bind) :value="value" 并在其脚本中:

  • 删除 Prop 值:对象或,
  • 如果您需要为 v-model 兼容性分配 value 属性,请将其分配给 File。例如:值:文件

注意:这可以工作,但是当在没有提供文件的情况下调用组件时,您会收到 Vue 警告:“类型检查失败”,因为无效的 prop。

即...

<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>

应该没问题。

关于javascript - 在 VueJS 应用程序中构建输入表单类型文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59710818/

相关文章:

带有单选按钮的 Javascript this.form.submit()

javascript - 构建仅用于 Chrome 应用程序的开发和运行时的 Vue

php - Vue.js 没有正确更新 URL

laravel - 如何查看 Laravel 中安装了哪个 Vue 版本以及如何更新?

javascript - vuex 中 Array .find() 方法参数未定义

javascript - 使文本左右两侧的图形根据文本量改变宽度?

javascript - 如何从 Javascript 调用 Jade 文件中的函数

javascript - jQuery Mobile : $(. ..).listview 不是函数

javascript - 如何通过jQuery onblur提交表单

javascript - Vue js vue cli3 应用程序在 ie11 中不起作用(babel 没有加载 polyfills?)