Vue多图上传组件删除错位、全局配置不生效、过渡动画失效问题求解
Vue图片上传表单问题修复方案
功能说明
实现了多图上传、预览功能,支持单张图片独立设置分类、类型、点赞数,也支持父页面全局配置统一应用到所有图片。
问题原因及修复方案
1. 删除组件后数据错位
- 原因:
v-for循环使用数组下标index作为key值,删除元素后下标重新排序,Vue会复用对应下标的组件而非重新渲染,导致组件内部数据和绑定的图片不匹配。 - 修复:给每个上传的文件生成唯一ID作为
key,避免组件复用错误。
2. 全局配置修改后不同步到已有子组件
- 原因:子组件仅在初始化时从props读取一次全局配置值,后续props更新不会同步到子组件内部的data变量。
- 修复:子组件添加
watch监听全局配置props的变化,变化后自动更新子组件内的对应字段。
3. fade过渡动画不生效
- 原因:单元素
transition组件不能作用于v-for循环的列表,且现有过渡样式缺少离开动画的过渡配置。 - 修复:改用
transition-group包裹循环列表,修正过渡样式。
修改后代码
upload.vue
<template> <div> <div> <!--全局分类选择,配置将应用到所有组件--> <v-select placeholder="Select Category" class="mt-2 md:w-1/2" :options="category" v-model="parentDesignCategory" /> <v-select placeholder="Select Type" class="mt-2 md:w-1/2" :options="type" v-model="parentDesignType" /> </div> <input type="file" accept="image/*" name="images" @change="uploadImage" id="images" multiple /> <div class="flex flex-wrap"> <!-- 改用transition-group处理列表过渡 --> <transition-group name="fade" tag="div"> <div class="md:w-1/2" v-for="(item, index) in files" :key="item.id"> <AdminFileUpload :file="item.file" :type="type" :category="category" :parentDesignType="parentDesignType" :parentDesignCategory="parentDesignCategory" @delete-row="deleteThisRow(index)" /> </div> </transition-group> </div> </div> </template> <script> export default { name: "admin", // middleware: "auth", data: function() { return { files: [], parentDesignType: null, parentDesignCategory: null, type: ["1", "2", "3"], category: ["a","b","c"] }; }, components: {}, methods: { uploadImage(event) { let fileList = event.target.files; for (let i = 0; i < fileList.length; i++) { // 每个文件加唯一ID作为key this.files.push({ id: Date.now() + Math.random(), file: fileList[i] }); } }, deleteThisRow: function(index) { this.files.splice(index, 1); } } }; </script> <style scoped> .fade-enter-active, .fade-leave-active { transition: opacity 1.5s ease; } .fade-enter-from, .fade-leave-to { opacity: 0; } </style>
fileUpload.vue
<template> <div> <div class="m-4"> <form @submit.prevent="uploadImage" class="flex flex-wrap w-full shadow-lg border border-black" action="/upload" > <div class="w-full md:w-1/2 p-2"> <div class="relative pb-1/1"> <img :src="imageSrc" class="w-full absolute h-full" /> </div> </div> <div class="flex flex-col w-full md:w-1/2 p-2"> <v-select placeholder="Select Category" class="mt-2" :options="category" v-model="designCategory" ></v-select> <v-select placeholder="Select Type" class="mt-2" :options="type" v-model="designType" ></v-select> <input placeholder="likes" class="w-full text-black border-2 mt-2 p-3 rounded-lg focus:outline-none focus:shadow-outline" type="number" v-model="designLikes" /> <button @click="removeSelf" class="uppercase h-12 text-lg font-bold tracking-wide bg-primary text-gray-100 mt-2 p-3 rounded-lg w-full cursor-pointer" type="button" > Cancel </button> <button type="submit" class="uppercase mt-2 h-16 text-xl font-bold tracking-wide bg-accent text-gray-100 p-3 rounded-lg w-full transition duration-300 hover:opacity-80 cursor-pointer" > Upload </button> </div> </form> </div> </div> </template> <script> import "vue-select/dist/vue-select.css"; export default { name: "fileUpload", middleware: "auth", props: [ "file", "type", "category", "parentDesignCategory", "parentDesignType" ], data() { return { designCategory: this.parentDesignCategory, designType: this.parentDesignType, designLikes: null }; }, watch: { // 监听全局配置变化,同步更新子组件值 parentDesignCategory(newVal) { this.designCategory = newVal; }, parentDesignType(newVal) { this.designType = newVal; } }, computed: { imageSrc: function() { return URL.createObjectURL(this.file); } }, methods: { async uploadImage() { let formData = new FormData(); const config = { headers: { "content-type": "multipart/form-data" } }; formData.append("likes", this.designLikes); formData.append("image", this.file); formData.append("category", this.designCategory); formData.append("type", this.designType); await this.$axios .post("upload", formData, config) .then(response => { this.showToast("Photo Uploaded.", "success"); // 上传完成后删除组件 this.$emit("delete-row"); }) .catch(error => {}); }, removeSelf: function() { this.$emit("delete-row"); } } }; </script>
内容的提问来源于stack exchange,提问作者mukeshsoni
相关产品推荐
相关产品推荐

