openks / learn-vue

自定义组件文档
https://openks.github.io/learn-vue
0 stars 0 forks source link

20180907___一个自定义文件上传组件的实现 #118

Open openks opened 6 years ago

openks commented 6 years ago

需求:实现一个自定义文件上传组件

  1. 需要的时候直接引入
  2. 轻松进行文件回填

    实现思路:

    1. 上传部分放到文件组件里实现
    2. 页面在上传成功后从服务端拉去图片显示(可优化)
    3. 删除时只移除已上传文件的 id(服务端未做处理,也可调用接口告诉服务端文件删除)
    4. 调用方只需关注 gotFile 事件
    5. 回填简单

原思路:

  1. 读取本地文件并展示在页面上(这样就不需要与服务端交互)
  2. 文件上传后只返回相关状态
  3. 问题:删除时无法确定删除的是那个文件,服务端与本地文件没有关联(一同事说可以使用文件名,更好的是使用一个前端生成的uuid,同时文件上传后返回这个uuid用于确定远程与本地文件的关联)

具体细节:

  1. 使用watch确保props获取到数据时本地data里的dfiles能够获取到props的数据
  2. 使用计算属性获取回填文件和自己上传文件的总文件
  3. 删除时分情况处理,即如果是自己上传的删除则自己上传的,如果是回填的则删除回填数据

面对回填问题时想到方案:

  1. 直接把props的值作为data的某一字段但是不行,props能获取到值而data的值却是空数组,无法获取
  2. 在mounted方法里把props的值赋值给data某一字段,经尝试发现在mounted时,props字段无法获取
<template>
    <div class="upload-new">
        <div class="add"
             @click="uploadClick">
            <i class="iconfont icon-add"></i>
        </div>
        <div v-for="(file, i) in allfiles"
             class='imgwrap'
             :key="i">
            <img :src="/file/'+file.name"
                 class="imgg">
            <span @click="delFile(file.uploadFileId)"
                  class="delete">
                <i class="iconfont icon-delete"></i>
            </span>
        </div>
        <input ref="upload"
               type="file"
               :multiple="multiple"
               hidden
               @change="uploadFile" />
    </div>
</template>
<script>
import { Indicator, Toast } from 'mint-ui';
export default {
    name: 'upload-file-new',
    props: {
        multiple: {
            default: false,
        },
        defaultFiles: {
            type: Array,
            default: function() {
                return [];
            },
        },
    },
    watch: {
        defaultFiles() {
            this.dfiles = this.defaultFiles;
        },
    },
    computed: {
        allfiles() {
            return this.dfiles.concat(this.files);
        },
    },
    data() {
        return {
            files: [],
            dfiles: [],
        };
    },
    methods: {
        uploadClick(val) {
            this.$refs.upload.click();
        },
        uploadFile(evt) {
            let items = evt.target.files;
            if (items.length > 0) {
                let formData = new FormData();
                let url = 'file/fileUpload';
                for (let i = 0; i < items.length; i++) {
                    formData.append('file', items[i]);
                }
                Indicator.open({
                    text: '文件上传中...',
                    spinnerType: 'fading-circle',
                });
                this.axios
                    .post(url, formData)
                    .then(res => {
                        Indicator.close();
                        if (res.data.code === '20000') {
                            let results = res.data.result;
                            for (let i = 0; i < results.length; i++) {
                                this.files.push(results[i]);
                            }
                            this.$emit('gotFile', this.allfiles);
                        } else {
                            Toast('文件上传失败');
                        }
                    })
                    .catch(err => {
                        Indicator.close();
                        Toast('文件上传异常,请联系管理员');
                        console.error(url, err);
                    });
            } else {
                console.log('ddddddddd');
            }
        },
        delFile(uploadFileId) {
            // 删除的是本次上传的
            let index = this.files.findIndex(
                ele => ele.uploadFileId === uploadFileId,
            );
            if (index > -1) {
                this.files.splice(index, 1);
            }
            let index2 = this.dfiles.findIndex(
                ele => ele.uploadFileId === uploadFileId,
            );
            if (index2 > -1) {
                this.dfiles.splice(index, 1);
            }
            console.log('index', index, uploadFileId, this.allfiles);
            this.$emit('gotFile', this.allfiles);
        },
    },
};
</script>
<style lang="less">
.upload-new {
    .add,
    .imgg {
        width: 60px;
        height: 60px;
        margin: 5px 0;
        border: 1px solid #d9d9d9;
    }
    .add {
        float: left;
        margin-right: 10px;
    }
    .icon-add {
        font-size: 62px;
        color: #d9d9d9;
    }
    .delete {
        position: absolute;
        right: 5px;
        top: 10px;
        width: 16px;
        height: 16px;
        display: block;
        background-color: #26a2ff;
        color: #fff;
        text-align: center;
    }
    .imgwrap {
        float: left;
        margin-right: 10px;
        position: relative;
    }
}
</style>