antd vue + axios 上传图片视频封装

本文档介绍了如何在Vue项目中,结合Ant Design Vue库和Axios实现图片及视频的上传功能。通过提供详细的antd组件代码和封装的请求js文件(request.js与index.js),阐述了上传过程的实现步骤和技术要点。

1.antd代码

<template>
  <div>
    <a-form
      ref="addForm"
      :form="form"
      @submit.prevent="onSubmit"
      :label-col=<
<think>我们正在使用Ant Design Vue 1.x封装一个上传组件,要求支持父组件控制fileList。这样父组件可以动态设置初始文件列表,并在上传过程中更新fileList(例如,在编辑时回显已上传的文件,或者在上传完成后添加新文件)。 关键点: 1.封装的组件中,使用`value`(或`fileList`)prop来接收父组件传递的文件列表。 2. 在组件内部,使用`a-upload`组件的`fileList`属性绑定这个prop,这样父组件就可以控制文件列表。 3. 由于`a-upload`组件内部会修改`fileList`(例如上传状态变化),我们需要在封装组件中监听变化并通知父组件(通过`input`事件或`update:value`事件,以实现双向绑定)。 4. 同时,我们也要支持自定义上传逻辑(customRequest)和上传前的校验(beforeUpload)。 注意:Ant Design Vue 1.x中,`a-upload`组件的`fileList`是受控的,所以我们需要通过事件来更新父组件的数据。 步骤: 1. 定义props,包括`value`(用于v-model绑定,类型为数组)和其他需要传递给a-upload的props(如action, multiple等)。 2. 在模板中,将a-upload的fileList绑定到value(或我们定义的prop)。 3. 监听a-upload的change事件,在change事件中,我们更新文件列表并触发input事件(或update:value事件)以便父组件更新。 4. 同时,我们也要支持beforeUpload和customRequest(如果需要自定义上传)。 另外,根据引用[2]中的示例,在编辑时,我们可以通过给fileList赋值来回显文件(如已经上传的文件)[^2]。 封装代码示例: ```vue <template> <a-upload :action="action" :fileList="value" // 绑定父组件传递的fileList :multiple="multiple" :beforeUpload="beforeUpload" :customRequest="customRequest || defaultRequest" // 支持自定义上传 @change="handleChange" :remove="handleRemove" :listType="listType" :accept="accept" > <!-- 根据listType显示不同的上传按钮 --> <div v-if="value.length < maxCount"> <a-icon type="plus" v-if="listType === 'picture-card'" /> <a-button v-else> <a-icon type="upload" /> 选择文件 </a-button> </div> </a-upload> </template> <script> export default { name: 'ControlledUpload', props: { value: { type: Array, default: () => [] }, action: { type: String, required: true }, multiple: { type: Boolean, default: false }, maxCount: { // 最多上传数量 type: Number, default: 1 }, listType: { type: String, default: 'text' // 可选: text, picture, picture-card }, accept: String, beforeUpload: Function, // 上传前的校验函数 customRequest: Function // 自定义上传函数 }, methods: { // 处理文件变化 handleChange(info) { let fileList = [...info.fileList]; // 限制最大上传数量 if (this.maxCount) { fileList = fileList.slice(-this.maxCount); } // 在这里可以做一些状态处理(如上传中、完成、失败等) // 但注意:fileList已经是响应式的,我们只需要将新的fileList通知给父组件 this.$emit('input', fileList); // 使用v-model时,触发input事件 // 或者使用 .sync 修饰符时,触发 update:value 事件 // this.$emit('update:value', fileList); }, // 处理文件移除 handleRemove(file) { // 移除文件时,直接由handleChange触发即可,因为handleChange会拿到新的fileList // 如果需要在移除时做一些额外操作,可以在这里做,然后触发一个remove事件 this.$emit('remove', file); }, // 默认的上传请求(如果父组件没有传递customRequest,则使用这个默认的) defaultRequest({ file, onProgress, onSuccess, onError }) { // 这里可以写默认的上传逻辑,比如使用FormData上传 const formData = new FormData(); formData.append('file', file); // 使用axios或fetch发送请求 // 注意:这里需要根据实际情况修改 axios.post(this.action, formData, { onUploadProgress: ({ total, loaded }) => { onProgress({ percent: Math.round(loaded / total * 100).toFixed(2) }, file); } }).then(response => { onSuccess(response, file); }).catch(error => { onError(error, file); }); } } }; </script> ``` 注意: 1. 我们使用了`value`作为prop,并监听内部变化后触发`input`事件,这样父组件可以使用`v-model`绑定。 2. 如果父组件需要.sync修饰符,可以触发`update:value`事件。 3. 我们支持了最大数量限制(maxCount),在handleChange中截取文件列表。 4. 支持自定义上传请求(customRequest),如果没有提供,则使用默认的defaultRequest(这里使用了axios,需要确保项目中有axios)。 5. 移除文件时,我们通过handleChange事件已经更新了fileList,所以不需要额外处理,但提供了一个remove事件供父组件监听。 父组件使用示例: ```vue <template> <div> <controlled-upload v-model="fileList" action="/api/upload" :maxCount="5" /> </div> </template> <script> import ControlledUpload from './ControlledUpload.vue'; export default { components: { ControlledUpload }, data() { return { fileList: [] // 初始为空,也可以从后台获取数据后赋值(用于编辑回显) }; } }; </script> ``` 编辑回显示例(如引用[2]所示): 在编辑时,我们可以将后台返回的文件信息构造成fileList需要的格式,然后赋值给fileList[^2]。 例如: ```javascript // 假设后台返回的图片地址是:http://example.com/image.png this.fileList = [{ uid: '-1', // 注意uid最好唯一,如果是已存在的文件,可以使用文件id name: 'image.png', status: 'done', // 状态为done表示已上传 url: 'http://example.com/image.png', }]; ``` 注意事项: - 文件状态(status)包括:'uploading', 'done', 'error', 'removed' - 在编辑时,我们通常将已上传的文件状态设置为'done',这样会显示为已上传状态。 - 在上传过程中,组件会自动更新文件状态,父组件只需要绑定fileList即可。 这样,我们就封装了一个支持父组件控制fileList的上传组件。</think># Ant Design Vue 1.x 封装支持父组件控制fileList的上传组件 在 Ant Design Vue 1.x 中封装支持父组件控制 `fileList` 的上传组件,可以更好地实现父子组件通信,方便在编辑模式下回显已上传文件。下面我将提供一个完整的解决方案,包含组件封装和示例使用场景。 ## 封装思路 1. 使用 `v-model` 实现双向绑定,让父组件可以控制 `fileList` 2. 支持编辑模式下回显已上传文件(参考引用[2]的回显方案) 3. 提供自定义上传逻辑的能力 4. 支持文件类型和大小验证 5. 实现上传状态反馈和错误处理 ## 封装后的上传组件代码 ```vue <template> <div class="controlled-upload"> <a-upload :action="action" :fileList="value" :multiple="multiple" :listType="listType" :accept="accept" :beforeUpload="handleBeforeUpload" :customRequest="customRequest" @change="handleChange" @preview="handlePreview" :remove="handleRemove" > <div v-if="value.length < maxCount"> <a-button v-if="listType !== 'picture-card'"> <a-icon type="upload" /> {{ buttonText }} </a-button> <div v-else> <a-icon type="plus" /> <div class="ant-upload-text">{{ buttonText }}</div> </div> </div> </a-upload> <!-- 预览模态框 --> <a-modal :visible="previewVisible" :footer="null" @cancel="previewVisible = false"> <img alt="预览" :src="previewImage" style="width: 100%" /> </a-modal> </div> </template> <script> export default { name: 'ControlledUpload', model: { prop: 'value', event: 'change' }, props: { // 使用v-model双向绑定fileList value: { type: Array, default: () => [] }, // 上传地址 action: { type: String, required: true }, // 是否多选 multiple: { type: Boolean, default: false }, // 上传类型:text/picture/picture-card listType: { type: String, default: 'text' }, // 接受的文件类型 accept: { type: String, default: 'image/*' }, // 最大上传数量 maxCount: { type: Number, default: 1 }, // 上传按钮文本 buttonText: { type: String, default: '点击上传' }, // 文件大小限制(MB) maxSize: { type: Number, default: 10 }, // 允许的文件类型 allowedTypes: { type: Array, default: () => ['image/jpeg', 'image/png', 'image/gif'] }, // 自定义上传方法(可选) customRequest: { type: Function, default: null } }, data() { return { previewVisible: false, previewImage: '', }; }, methods: { // 上传前验证 handleBeforeUpload(file) { // 文件类型验证 const isAllowedType = this.allowedTypes.includes(file.type); if (!isAllowedType) { this.$message.error(`仅支持上传 ${this.allowedTypes.join(', ')} 格式的文件`); return false; } // 文件大小验证 const isLtMaxSize = file.size / 1024 / 1024 < this.maxSize; if (!isLtMaxSize) { this.$message.error(`文件大小不能超过 ${this.maxSize}MB`); return false; } // 触发父组件的beforeUpload钩子 if (this.$listeners.beforeUpload) { return this.$listeners.beforeUpload(file); } return true; }, // 处理文件变化 handleChange(info) { let fileList = [...info.fileList]; // 限制最大数量 if (this.maxCount) { fileList = fileList.slice(-this.maxCount); } // 更新状态 fileList = fileList.map(file => { if (file.response) { // 上传成功时,设置URL file.url = file.response.url; } return file; }); // 触发v-model更新 this.$emit('change', fileList); // 上传状态处理 if (info.file.status === 'done') { this.$message.success(`${info.file.name} 上传成功`); this.$emit('success', info.file.response); } else if (info.file.status === 'error') { this.$message.error(`${info.file.name} 上传失败`); this.$emit('error', info.file.error); } }, // 处理文件移除 handleRemove(file) { // 触发父组件的remove事件 this.$emit('remove', file); return true; }, // 处理预览 handlePreview(file) { this.previewImage = file.url || file.thumbUrl; this.previewVisible = true; }, // 默认上传方法(当未提供customRequest时使用) defaultRequest({ file, onProgress, onSuccess, onError }) { const formData = new FormData(); formData.append('file', file); // 使用axios或fetch实现上传 const config = { onUploadProgress: ({ total, loaded }) => { onProgress({ percent: Math.round(loaded / total * 100) }, file); } }; // 这里使用fetch作为示例,实际项目中可以使用axios fetch(this.action, { method: 'POST', body: formData, ...config }) .then(response => response.json()) .then(data => { onSuccess(data, file); }) .catch(error => { onError(error, file); }); } } }; </script> <style scoped> .controlled-upload { margin: 20px 0; } /* 图片卡片样式调整 */ :deep(.ant-upload.ant-upload-select-picture-card) { margin-bottom: 0; } </style> ``` ## 在父组件中使用示例 ```vue <template> <div class="upload-container"> <h2>封装上传组件示例</h2> <div class="upload-section"> <h3>单张图片上传(编辑模式回显)</h3> <controlled-upload v-model="avatarFileList" action="/api/upload" listType="picture-card" :maxCount="1" buttonText="上传头像" @success="handleUploadSuccess" @remove="handleRemoveAvatar" /> </div> <div class="upload-section"> <h3>多文件上传</h3> <controlled-upload v-model="documentsFileList" action="/api/upload" :multiple="true" :maxCount="3" accept=".pdf,.doc,.docx" buttonText="上传文档" :allowedTypes="['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']" @beforeUpload="customBeforeUpload" /> <p class="upload-hint">最多可上传3个PDF或Word文档</p> </div> <div class="upload-section"> <h3>自定义上传逻辑</h3> <controlled-upload v-model="customFileList" :customRequest="customUploadHandler" buttonText="自定义上传" :maxSize="50" /> </div> <div class="actions"> <a-button type="primary" @click="submitAll">提交所有文件</a-button> <a-button @click="resetAll">重置</a-button> </div> </div> </template> <script> import ControlledUpload from './components/ControlledUpload.vue'; export default { components: { ControlledUpload }, data() { return { // 头像上传(模拟编辑模式下回显) avatarFileList: [ { uid: '-1', name: 'avatar.png', status: 'done', url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', } ], // 文档上传 documentsFileList: [], // 自定义上传 customFileList: [] }; }, methods: { // 处理上传成功 handleUploadSuccess(response) { console.log('上传成功:', response); this.$message.success('文件上传成功'); }, // 处理移除头像 handleRemoveAvatar(file) { console.log('移除文件:', file); }, // 自定义上传前验证 customBeforeUpload(file) { console.log('自定义验证:', file); return true; }, // 自定义上传处理 customUploadHandler({ file, onProgress, onSuccess, onError }) { console.log('自定义上传处理:', file); // 模拟上传进度 let progress = 0; const interval = setInterval(() => { progress += 10; onProgress({ percent: progress }, file); if (progress >= 100) { clearInterval(interval); // 模拟上传成功响应 onSuccess({ url: `https://example.com/files/${file.name}`, id: Date.now() }, file); } }, 300); }, // 提交所有文件 submitAll() { console.log('提交所有文件:'); console.log('头像:', this.avatarFileList); console.log('文档:', this.documentsFileList); console.log('自定义:', this.customFileList); this.$message.info('已提交所有文件信息'); }, // 重置所有上传 resetAll() { this.avatarFileList = []; this.documentsFileList = []; this.customFileList = []; this.$message.success('已重置所有上传'); } } }; </script> <style scoped> .upload-container { max-width: 800px; margin: 0 auto; padding: 20px; background-color: #fff; border-radius: 8px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); } .upload-section { margin-bottom: 30px; padding: 20px; border: 1px solid #e8e8e8; border-radius: 4px; background-color: #fafafa; } .upload-hint { color: #999; font-size: 12px; margin-top: 8px; } .actions { margin-top: 20px; text-align: center; } .actions button { margin: 0 10px; } h2 { text-align: center; color: #1890ff; margin-bottom: 30px; } h3 { color: #333; margin-bottom: 15px; } </style> ``` ## 关键特性说明 1. **v-model双向绑定**: - 使用 `model` 选项配置 `v-model` 的双向绑定 - 父组件通过 `v-model` 控制 `fileList`,子组件通过 `$emit('change')` 更新 2. **编辑模式回显**: - 父组件可以设置初始 `fileList`(如引用[2]所示) - 文件状态设置为 `done` 表示已上传完成 3. **灵活的验证机制**: - 内置文件类型和大小验证 - 支持通过 `beforeUpload` 事件自定义验证逻辑 4. **自定义上传处理**: - 通过 `customRequest` prop 支持自定义上传实现 - 提供默认上传方法作为备用 5. **预览功能**: - 内置图片预览模态框 - 支持点击预览上传的文件 6. **响应式设计**: - 支持三种列表类型:text/picture/picture-card - 自适应布局 ## 应用场景 1. **用户头像上传**:使用 `picture-card` 类型,限制最大数量为1 2. **多文件文档上传**:使用 `text` 类型,支持PDF/Word等文档格式 3. **自定义上传逻辑**:集成第三方存储服务(如阿里云OSS、七牛云等) 4. **编辑模式**:从API获取已上传文件并回显 这个封装组件解决了Ant Design Vue 1.x中父组件难以控制上传状态的问题,提供了更灵活的文件管理能力,同时保持了原组件良好的用户体验。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱芙淘趣坊

为嗷嗷待哺的我助力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值