美文网首页For Full Stack
Vue 图片/文件上传组件 -- 轻量版 NPM vue-im

Vue 图片/文件上传组件 -- 轻量版 NPM vue-im

作者: MercuryWang | 来源:发表于2019-02-17 23:59 被阅读0次

    2020.1.20 更新:

    Vue 组件发布到 npm,安装:

    npm i vue-image-pdf-uploader
    

    HTML 代码:

    <div id="root">
      <div class="main-container">
        <div class="image-container">
          <div class="click-to-upload" v-if="!(imgList.length | pdfList.length)" @click="addFilesClick">点击添加文件</div>
    
          <div class="image-wrap" v-for="(image, index) in imgList">
            <img class="delete-icon" src="/public/images/www/icon/delete.png" @click="deleteImg(index)" alt="">
            <img class="portfolio-image" :src="image.file.src" alt="">
          </div>
    
          <div class="pdf-wrap" v-for="(pdf, index) in pdfList">
          <img class="delete-icon" src="/public/images/www/icon/delete.png" @click="deletePdf(index)" alt="">
          <img class="pdf-icon" src="/public/images/www/icon/file_pdf.png" alt="">
          <span class="pdf-name" v-text="pdf.file.name"></sapn>
        </div>
        </div>
    
        <input @change="fileChange($event)" type="file" id="upload_file" multiple style="display: none"/>
        <div class="img-count">共 <span v-text="imgList.length + pdfList.length"></span> 个文件 (<span v-text="formattedSize"></span>)
      {# 已上传 {{ count }} 个 #}</div>
        <span v-if="imgList.length | pdfList.length" class="continue-to-upload" @click="addFilesClick">继续添加</span>
      </div>
    

    这里的 input 元素是隐藏的,在 div.click-to-upload 元素上绑定事件 addFilesClick,方法内获取 input 元素的 id 然后绑定 input 的 click 事件。


    JavaScript 代码:

    import Vue from 'vue';
    import 'whatwg-fetch';
    
    let vm = new Vue({
        el: '#root',
        data: {
            imgList: [],
            size: 0,
            formattedSize: '0 B',
            pdfList: [],
            name: '',
            email: '',
            tel: '',
        },
    
        methods: {
            addFilesClick() {
                document.getElementById('upload_file').click();
            },
    
            fileChange(event) {
          let files = event.target.files;
          for (let i = 0; i < files.length; i++) {
            this.addFile(files[i]);
          }
        },
    
            addFile(file) {
                //统计文件 size
                this.size = this.size + file.size;
                this.calculateFileSize(this.size);
    
                //1. 如果是图片文件
                if (file.type.indexOf('image') >= 0) {
                    let reader = new FileReader();
                    let image = new Image();
                    let _this = this;
                    reader.readAsDataURL(file);
                    reader.onload = function() {
                        file.src = this.result;
                        image.onload = function() {
                            let width = image.width;
                            let height = image.height;
                            file.width = width;
                            file.height = height;
                            _this.imgList.push({ file });
                        };
                        image.src = file.src;
                    };
                }
    
                //2. 如果是 pdf 文件
                if (file.type.indexOf('pdf') >= 0) {
                    this.pdfList.push({ file });
                }
            },
    
            deleteImg(index) {
                //重新统计 file size
                this.size = this.size - this.imgList[index].file.size;
                this.calculateFileSize(this.size);
                this.imgList.splice(index, 1);
            },
    
            deletePdf(index) {
                //重新统计 file size
                this.size = this.size - this.pdfList[index].file.size;
                this.calculateFileSize(this.size);
                this.pdfList.splice(index, 1);
            },
    
            // file size 单位转换
            calculateFileSize(bytes) {
                let _this = this;
                if (bytes === 0) _this.formattedSize = '0 B';
                else {
                    let k = 1024,
                        unit = ['B', 'KB', 'MB'],
                        i = Math.floor(Math.log(bytes) / Math.log(k));
                    let result = (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + unit[i];
                    _this.formattedSize = result;
                }
            },
    
            submitFiles() {
                //获取页面最终保留的 files' name
                let imgList = this.imgList;
                let fileList = [];
                for (let i = 0; i < imgList.length; i++) {
                    fileList.push(imgList[i].file.name);
                }
               .....
        },
    });
    

    点击确认上传之前,图片是暂存在本地一个临时文件夹中的,其中包含了所有文件,也就是说前台页面删除了,临时文件夹下还保留着。所以最后需要获取下前台页面中保留的文件名称,与临时文件夹下的文件进行 match,如果匹配则提交后台数据库。


    CSS 代码:

    .main-container {
      min-height: 120px;
      height: auto;
      width: 720px;
      position: relative;
    }
    
    .image-container {
      width: 720px;
      min-height: 110px;
      height: auto;
      display: flex;
      flex-wrap: wrap;
      text-align: center;
      line-height: 120px;
      border-bottom: 1px solid #000000;
      padding-top: 10px;
    }
    
    .click-to-upload {
      color: orangered;
      text-decoration: underline;
      text-decoration-color: orangered;
      width: 100%;
      cursor: pointer;
      line-height: 90px;
    }
    
    .image-wrap,
    .pdf-wrap {
      width: 95px;
      height: 120px;
      overflow: hidden;
      position: relative;
      margin-right: 25px;
      margin-bottom: 30px;
      text-align: center;
      line-height: 120px;
    }
    
    .pdf-wrap {
      border: #585858 1px solid;
    }
    
    .pdf-wrap:hover .delete-icon {
      display: block;
    }
    
    .pdf-icon {
      width: 40px;
      height: 45px;
      position: absolute;
      top: 20px;
      left: 35px;
    }
    
    .portfolio-image {
      width: auto;
      height: auto;
      vertical-align: middle;
      // max-width: 100%;
      max-height: 100%;
    }
    
    .delete-icon {
      width: 20px;
      height: 20px;
      position: absolute;
      display: none;
      right: 0;
      top: 0;
    }
    
    .image-wrap:hover .delete-icon {
      display: block;
    }
    
    .continue-to-upload {
      width: 80px;
      line-height: 60px;
      position: absolute;
      right: 30px;
      text-decoration: underline;
      cursor: pointer;
    }
    
    .img-count {
      line-height: 60px;
      display: inline;
    }
    
    .btn {
      display: block;
    }
    
    .pdf-name {
      position: relative;
      bottom: -25px;
      font-size: 12px;
    }
    
    .submit {
      cursor: pointer;
      background-color: #e3e4e5;
      text-decoration: underline;
    }
    
    .underline {
      text-decoration: underline;
    }
    

    相关文章

      网友评论

        本文标题:Vue 图片/文件上传组件 -- 轻量版 NPM vue-im

        本文链接:https://www.haomeiwen.com/subject/ljfoeqtx.html