在实现公司业务时,打算自己一个文件上传组件,于是着手写了一下,下面是实现步骤:
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的原因