The upload component of ANTD directly triggers uploading to the server through action. Click upload to upload a file and upload a file to the server once. The multiple attribute only supports the selection of multiple files, which can be directly uploaded after selection. And can delete the file before the submission of operations how to achieve?

To implement manual upload, we can implement our own upload logic with the help of the customRequest property provided by the Upload component.

For example, in ANTD Pro of Vue, we implement a form submission with associated images

1. This form has editing and adding functions. When editing, we can get the list of existing pictures and make a difference between a given type and the newly added one.

We hid the list of files that came with the component, and then created a custom picture list to show the uploaded images, on which we defined some preview and delete actions to control our photo wall.

3. Before uploading, use the beforeUpload method to limit the type, format, size and relevant prompts of uploaded images.

Render the obtained content to the photo wall. Some plugin. will return the base64 address of the image, but ANTD does not return, we can use FileReader to change the image to base64 address.

5. Get the content and push it into the file list, then manually submit the form and pass the file to the server using formData().

6. We can use the onUploadProgress attribute of the data request API to monitor the interface submission progress, so as to realize the upload percentage progress bar.

Similarly, other upload functions can be similarly handled. If you want to display each file with a progress bar, you can either change the business requirements and directly use the default function of the component, using action to upload directly, so that each picture has its own progress bar, and you can also customize the style and effect of uploading according to the properties. If you upload together and each file has a progress bar, because the interface transfer time, only one time schedule, so we must use the Promise when click submit multiple call interface at the same time, an interface to upload a file, so that each file have a progress bar, actually, so it is better to use the default upload directly.

<template>
  <a-modal title="Submit relevant information" :visible="true" width="1000px" @cancel="closeDialog">
    <a-form-model ref="editForm" :model="formData" :rules="formRule" :label-col="{span: 3}" :wrapper-col="{span:18}">
    
        <a-form-model-item label="Name" prop="name">
            <a-input v-model="formData.name" placeholder="Please enter a name"></a-input>
        </a-form-model-item>

        <a-form-model-item label="Related pictures">
            <div class="relate-image">
                <div class="image-list">

                    <! -- List of uploaded images -->
                    <div class="list-item" v-for="(item, index) in uploadImg.showImages" :key="item.url">
                        <img v-if="item.type=='origin'" :src="baseUrl+item.url" alt="Related pictures">
                        <img v-else :src="item.url" alt="Related pictures">
                        <! Preview - - - >
                        <div class="item-hover">
                            <a-icon style="margin-right: 10px;" type="eye" @click="openPreview(index)" />
                            <a-icon type="delete" @click="deleteRelateImg(index)" />
                        </div>
                    </div>

                    <! -- Upload component, hide more than 5 pictures -->
                    <a-upload 
                        style="width: 104px;" 
                        v-if="uploadImg.showImages && uploadImg.showImages.length < 5" 
                        action="#" 
                        list-type="picture-card"
                        accept=".jpg, .png"
                        :show-upload-list="false"
                        :before-upload="beforeUpload" 
                        :customRequest="customUpload"
                    >
                        <a-icon type="plus" />
                        <div class="ant-upload-text">upload</div>
                    </a-upload>
                </div>
                <! -- Upload progress -->
                <a-progress v-if="btnLoading" :percent="uploadProgress" />

                <a-modal :visible="uploadImg.previewVisible" :footer="null" @cancel="closePreview">
                    <img alt="example" style="width: 100%" :src="uploadImg.previewImage" />
                </a-modal>
            </div>
        </a-form-model-item>

    </a-form-model>

    <template slot="footer">
        <a-button @click="closeDialog">cancel</a-button>
        <a-button type="primary" :loading="btnLoading" @click="editConfirm">determine</a-button>
    </template>

  </a-modal>
</template>

<script>
import { saveApi } from '@/api/save.js'
export default {
    name: 'SaveFile'.props: {
        editData: {
            type: Object.default () {
                return{}}}},data() {
      return {
        baseUrl: process.env.VUE_APP_API_BASE_URL,
        btnLoading: false.formRule: {
            name: [{required: true.message: 'Please enter a name'.trigger: 'blur'}],},// Form data
        formData: {},
        uploadProgress: 0.// Upload progress

        // Image upload
        uploadImg: {
            showImages: [].// Related pictures
            previewVisible: false.previewImage: ' '}}},created() {
      this.getFromData();
    },
    methods: {
        // Get form data
        getFromData() {
            if (this.editData.type == 'edit') {
                this.formData = this.editData.data;
            } else {
                this.formData = {
                    id: 0.name: ' '.images: [].}}// The form displays an existing image
            // This depends on your situation
            let showImages = [];
            this.formData.images.forEach(item= > {
                let ob = {
                    type: 'origin'.url: item
                }
                showImages.push(ob);
            });
            this.uploadImg.showImages = showImages;
        },

        // Limit images before uploading
        beforeUpload(file) {
            const { type, size } = file;
            const limitType = type === 'image/jpeg' || type === 'image/png';
            if(! limitType) {this.$message.error('Please upload JPG, PNG image! ');
            }
            const limitSize = size / 1024 / 1024 < 2;
            if(! limitSize) {this.$message.error('Images cannot be larger than 2MB! ');
            }
            return limitType && limitSize;
        },

        // Customize upload to obtain file content
        async customUpload(fileInfo) {
            const { file } = fileInfo;
            try {
                const url = await this.fileToBase64(file); // Get the base64 address
                let ob = {
                    type: 'upload', 
                    url,
                    file
                }
                this.uploadImg.showImages.push(ob);
            } catch (err) {
                this.$message.error(err.message); }},// Convert the image address
        fileToBase64(file) {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            return new Promise((resolve, reject) = > {
                reader.onload = function (e) {
                    if (this.result) {
                    resolve(this.result)
                    } else {
                    reject("Image conversion error, please try again later.")}}})},// Photo wall preview
        openPreview(index) {
            // The base64 address is directly displayed when the server uploads it, which is determined by the path of the image returned by the backend
            if (this.uploadImg.showImages[index].type === 'upload') {
                this.uploadImg.previewImage = this.uploadImg.showImages[index].url;
            } else {
                this.uploadImg.previewImage = this.baseUrl + this.uploadImg.showImages[index].url;
            }
            this.uploadImg.previewVisible = true;
        },

        closePreview() {
            this.uploadImg.previewVisible = false;
        },

        // Delete the uploaded image
        deleteRelateImg(index) {
            let that = this;
            this.$confirm({
                title: 'Are you sure to delete the picture? `.okType: 'danger'.onOk() {
                    that.uploadImg.showImages.splice(index, 1); }}); },// Submit the form
        editConfirm() {
            this.$refs.editForm.validate(valid= > {
                if (valid) {
                    // Submit in formData format
                    const formData = this.formatData();
                    this.btnLoading = true;

                    // A custom request, based on its own encapsulation of axios
                    saveApi(formData, {
                        // Get the file upload progress
                        onUploadProgress: function (e) {
                            var completeProgress = ((e.loaded / e.total * 100) | 0);
                            that.uploadProgress = completeProgress;
                        }
                    })
                    .then(res= > {
                        this.btnLoading = false;
                        if(res.code ! =200) {
                            this.$notification.error({
                                message: 'wrong'.description: res.msg
                            })
                            return false
                        }
                        this.$message.success('Submission successful! ');
                    })
                    .catch(err= > {
                        this.btnLoading = false;
                        this.uploadProgress = 0;
                        this.$notification.error({
                            message: 'wrong'.description: err.response.data.msg
                        })
                    })
                } else {
                    this.$message.warning("Incomplete form filling"); }}); },// Convert the formData format
        formatData() {
            // The file content is submitted in formData format. FormData format cannot be printed directly.
            // If the content is an array, append by append through the for loop
            // If the content is a JSON object, it needs to be submitted using json.stringify (obj)

            const { id, name } = this.formData;
            let formData = new FormData();
            formData.set('id', id);
            formData.set('name', title);

            // Distinguish the original image from the uploaded image, parameters and back-end defined
            let originImages = this.uploadImg.showImages.filter(item= > item.type == 'origin');
            if (originImages && originImages.length) {
                originImages.forEach(item= > {
                    formData.append('attach[]', item.url)
                })
            }
            let uploadImages = this.uploadImg.showImages.filter(item= > item.type == 'upload');
            if (uploadImages && uploadImages.length) {
                uploadImages.forEach(item= > {
                    formData.append('file[]', item.file)
                })
            }
            return formData
        },

        closeDialog() {
            this.$emit('CLOSE_DIALOG_EVENT'); }}},</script>
<style lang="less" scoped>
.relate-image {
    display: flex;
    width: 100%;

    .image-list {
        width: 100%;
        display: flex;
        flex-wrap: wrap;

        .list-item {
            position: relative;
            height: 104px;
            margin: 0 8px 8px 0;
            padding: 8px;
            border: 1px solid #D9D9D9;
            border-radius: 4px;

            img {
                min-width: 50px;
                height: 100%;
            }

            .item-hover {
                position: absolute;
                top: 50%;
                left: 50%;
                z-index: 9;
                display: none;
                justify-content: center;
                align-items: center;
                width: calc(100% - 16px);
                height: 88px;
                color: #fff;
                background: rgba(0.0.0.2);
                transform: translate(-50%, -50%);
                cursor: pointer;
            }

            &:hover .item-hover {
                display: flex; }}}}</style>
Copy the code