在实现公司业务时,打算自己一个文件上传组件,于是着手写了一下,下面是实现步骤:
1、先是手动创建一个上传按钮样式,实现如下:

<template>    <div class="preview" >        <span class="removeBtn" @click="removePic"><van-icon name="delete"></van-icon></span>    </div>    <div class="diy-upload">        <div class="plus">+</div>        <input v-if="columnName === '视频'"               class="videoInput"               type="file"               accept="video/*"               @change="uploadFile($event)"               name="fileTrans">        <input v-if="columnName === '文档'"               class="videoInput"               type="file"               accept=".doc, .docx, .xml, .xlsx"               @change="uploadFile($event)"               name="fileTrans">        <input v-if="columnName === '音频'"               class="videoInput"               type="file"               accept="audio/*"               @change="uploadFile($event)"               name="fileTrans">        <input v-if="columnName === '图片'"               class="videoInput"               accept="image/*"               type="file"               @change="uploadFile($event)"               name="fileTrans">        <input class="diy-submit" type="submit"/>    </div></template><style lang="less" scoped>    .upload{        padding: 140px 36px 160px 36px;        box-sizing: border-box;    }    .diy-upload{        position: relative;        margin: 0 auto;        width: 160px;        height: 160px;        display: flex;        align-items: center;        justify-content: center;        box-sizing: border-box;        background-color: #fff;        border: 2px dashed #e5e5e5;        cursor: pointer;        .plus{            color: #969799;            font-size: 24px;            /*z-index: 666;*/            position: absolute;            top: 0;            left: 0;            width: 160px;            height: 160px;            /*background: #333333;*/            text-align: center;            line-height: 160px;        }        .videoInput{            position: absolute;            width: 160px;            height: 160px;            overflow: hidden;            opacity: 0;        }    }    .preview{        position: relative;        margin-top: 10px;        display: none;        /*border: 2px solid #dedede;*/        text-align: center;        span:nth-of-type(1){            width: 32px;            height: 32px;            position: absolute;            right: 0;            bottom: 0;            z-index: 10000;            font-size: 26px;            color: #fff;        }        span:nth-of-type(2){            width: 30px;            height: 30px;            text-align: center;            line-height: 30px;            position: absolute;            top: -15px;            right: -15px;        }    }    .diy-detail{        width: 100%;        overflow: hidden;        .btn{            span{                margin-bottom: 10px;            }        }        .van-cell{            background-color: #F0F0F0;            border-radius: 35px;            font-size: 26px;            height: 69px;            line-height: 69px;            padding: 0 22px;            color: #999;        }        .van-hairline--top-bottom::after, .van-hairline-unset--top-bottom::after {            border-width: 0;        }        p{            height: 64px;            line-height: 64px;            font-size: 32px;            color: #333;            position: relative;            padding-left: 16px;        }        p::before{            position: absolute;            top: 0;            left: 0;            content: '*';            color: #FF0000;        }        span{            display: inline-block;            width: 157px;            background: #F0F0F0;            border-radius: 35px;            color: #999;            font-size: 26px;            padding: 14px 18px;            margin-right: 28px;            text-align: center;        }        .active{            color: #fff;            background: linear-gradient(to right,#FD5130,#FA6C34);        }    }    .diy-submit {        position: fixed;        height: 150px;        width: 90%;        bottom: 0;        background: #fff;        .van-button {            width: 100%;            height: 90px;            border-radius: 45px;            font-size: 36px;            color: #fff;            background: linear-gradient(to right, #FD5130, #FA6C34);            top: 50%;            transform: translate(0, -50%);        }        .van-button--default {            border: none;        }    }</style>

样式如下

功能实现如下:

<script>    import VHeader from '../../common/header'    import {classifyList, uploadFile, addResources} from '../../http/mock'    import Toast from 'vant'    export default {        name: "uploadFile",        components: {            VHeader        },        data(){            return{                tagList: [],                uploadTitle: '',                currentTag: null,                tagId: null,                columnName: localStorage.getItem('columnName'),                fileIdArr: [],                uploadVideoList: [],                videoSrc: '',                uploadDocList: [],                uploadAudioList: [],                uploadPicList: [],                picSrc: '',            }        },        filters: {            formatSize(val) {                if (val > 0) {                    return (val / 1024 / 1024).toFixed(2) + 'M';                } else {                    return '0M';                }            },        },        methods: {            uploadFile(val){                let input = document.querySelector('input');                let preview = document.querySelector('.preview');                let uploadDiv = document.querySelector('.diy-upload');                let timerDesc = document.querySelector('.timer');                uploadDiv.style.display = 'none';                preview.style.display = 'block';                let files = input.files;                if (!files.length){                    return;                }                let size = files[0].size/1024/1024;  // 獲取文件的大小                let columnName = localStorage.getItem('columnName')                let formData = new FormData();                let config = {                    headers: {                        'Content-Type': 'multipart/form-data'                    }                };                if(columnName === '视频'){                    formData.append(encodeURI(val.target.files[0].name), val.target.files[0]);                    let video = document.createElement('video');                    video.className = 'addDiv';                    video.style.maxHeight = '215px';                    video.style.width = '100%';                    video.src = files[0].name;                    timerDesc.innerHTML = '上傳時間:' + this.$moment(files[0].lastModifiedDate).format('YYYY-MM-DD');                    preview.style.background = '#000';                    preview.appendChild(video);                    video.src = window.URL.createObjectURL(files[0]);                    video.autoPlay = 'autoplay';                    video.preload = 'auto';                } else if(columnName === '文档'){                    formData.append(encodeURI(val.target.files[0].name), val.target.files[0]);                    preview.style.textAlign = 'left';                    let doc =  document.createElement('div');                    let docImg = document.createElement('img');                    let docTitle = document.createElement('span');                    let docSize = document.createElement('span');                    doc.className = 'addDiv';                    docImg.style.display = 'inline-block';                    docImg.style.cssFloat = 'left';                    docImg.style.width = '28px';                    docImg.style.height = '28px';                    docImg.style.marginRight = '5px';                    docImg.src = require('../../assets/img/resource_doc_b@2x.png');                    docTitle.style.cssFloat = 'left';                    docTitle.style.fontSize = '14px';                    docTitle.style.marginRight = '30px';                    docTitle.style.lineHeight= '28px';                    docTitle.innerText = files[0].name;                    docSize.style.cssFloat = 'left';                    docSize.style.lineHeight= '28px';                    docSize.innerText = size.toFixed(2) + 'M';                    doc.appendChild(docImg);                    doc.appendChild(docTitle);                    doc.appendChild(docSize);                    preview.appendChild(doc);                } else if(columnName === '音频'){                    formData.append(encodeURI(val.target.files[0].name), val.target.files[0]);                    preview.style.textAlign = 'left';                    let audioDiv = document.createElement('div');                    let audioImg = document.createElement('img');                    let audioTitle = document.createElement('span');                    let audioSize = document.createElement('span');                    audioDiv.className = 'addDiv';                    audioImg.style.display = 'inline-block';                    audioImg.style.cssFloat = 'left';                    audioImg.style.width = '28px';                    audioImg.style.height = '28px';                    audioImg.style.marginRight = '5px';                    audioImg.src = require('../../assets/img/resource_audio@2x.png');                    audioTitle.style.cssFloat = 'left';                    audioTitle.style.marginRight = '30px';                    audioTitle.style.fontSize = '14px';                    audioTitle.style.lineHeight = '28px';                    audioTitle.innerText = files[0].name;                    audioSize.style.cssFloat = 'left';                    audioSize.style.lineHeight = '28px';                    audioSize.innerText = size.toFixed(2) + 'M';                    audioDiv.appendChild(audioImg);                    audioDiv.appendChild(audioTitle);                    audioDiv.appendChild(audioSize);                    preview.appendChild(audioDiv);                }else if(columnName === '图片'){                    formData.append(encodeURI(val.target.files[0].name), val.target.files[0]);                    preview.style.textAlign = 'center';                    preview.style.background = '#000';                    preview.style.width = '100%'                    let picImg = document.createElement('img');                    picImg.className = 'addDiv';                    picImg.src =  window.URL.createObjectURL(files[0]);                    console.log(picImg.src);                    picImg.style.width = '100%';                    picImg.style.maxHeight = '215px';                    picImg.style.margin = '0 auto';                    preview.appendChild(picImg);                }                this.$api.post(uploadFile, formData, config).then(res => {                    this.fileIdArr = res.data.data;   // 把選中的文件傳送給後台                }).catch(err => {                    Toast('文件上傳失敗!')                })            },            // 移除创建的所有元素,并显示隐藏上传按钮            removePic(){                let uploadDiv = document.querySelector('.diy-upload');                let timerDesc = document.querySelector('.timer');                let preview = document.querySelector('.preview');                let image = preview.querySelector('.addDiv');                preview.removeChild(image);                preview.style.display = 'none';                uploadDiv.style.display = 'block';                timerDesc.innerHTML = '';                // console.log('input', document.querySelector('input'));            },            doSubmit(){                let params = {                    classify: this.tagId,        // 针对视频资源时对应的分类id                    file: this.fileIdArr,   // 选择完文件后,调用uploadFile这个接口,后端返回的数组                    resourceColumnId: JSON.parse(localStorage.getItem('columnId')),   // 资源栏目id(视频、图片、音频、文档)                    title: this.uploadTitle    // 上传时填写的标题                };                let columnName = localStorage.getItem('columnName')                this.$api.post(addResources, params).then(res => {                    if(res.data.code === 1001){                        if(columnName === '视频'){                            this.$router.push({name: 'myVideo'});                        }else {                            this.$router.push({name: 'myResourceClassify'});                        }                    }                }).catch(err => {                    console.log(err)                })            },        },    }</script>

这段代码有点bug,就是当选中了上传的文件后,再把选中的文件删除掉,不能再选中前面选中过的,这个bug初步判断是因为,再次选中删除的文件,此时文件不能再被选中,导致没有获取到当前文件,还需要再进一步排查解除产生bug的原因