多图上传组件vue

前言

小编参加的第一个项目,就遇到了麻烦的多图上传,通过多天的努力,写出了一个多图的组件,希望可以帮助到大家

组件template部分

多图上传按钮+多图上传弹窗+图片上的预览删除图标

<template>
<div>
    <div class="many">
      <el-form-item>
        <div class="upload-item">
          <el-button type="primary" @click="uploadFile">多图上传</el-button>
        </div>
      </el-form-item>
    </div>

  <el-dialog title="图片预览" :visible.sync="dialogImgVisible" width="50%">
    <img :src="dialogImageUrl" alt="" class="previewImg" />
  </el-dialog>


  <!--多图上传弹窗界面-->
<el-dialog :title="'上传'" :visible.sync="dialogFormVisible" custom-class="pub_dialog" >
  <el-form style="width: 750px;height: 380px">
    <!--内容部分  -->
    <el-form-item><!---->
        <div style="display: flex;justify-content: center">
          <label>选择文件:</label>
          <div>
            <div class="desc">支持 jpg, png 图片格式,且不超过500kb</div>
            <el-upload
                :action="UPLOAD_URL"
                :headers="authorToken"
                :auto-upload="true"
                accept="image/jpg,image/png,image/jpeg"
                :on-success="handleSuccess"
                :before-upload="handleBeforeUpload"
                :show-file-list="false"
                multiple
                :limit="10"
                :on-exceed="handleExceed"
                :file-list="fileList">
              <el-button size="small" type="primary">上传图片</el-button>
            </el-upload>
          </div>
        </div>

          <div class="fileList" style="margin-top: 10px;display: flex;flex-wrap: wrap;">
            <div class="item" v-for="(item,index) in images" :key="index">
              <img :src="item.url" alt="" :key="index" style=" width: 45%;height: 100%" class = "imgList">
              <div class="scissor-icon">
                <i class="el-icon-scissors" @click="changeFile(item)"></i>
              </div>
              <div class="delete-icon">
                <i class="el-icon-delete" @click="handleRemove(item)"></i>
              </div>
              <div class="search-icon">
                <i class="el-icon-search" @click="handlePreview(item)"></i>
              </div>
              <el-input
                  type="textarea"
                  :autosize="{ minRows: 7, maxRows: 7}"
                  placeholder="请输入图片描述"
                  v-model="item.manyDescription"
                  :key="index"
                  style=" width: 55%;height: 100%;margin-left: 10px">
              </el-input>
            </div>
          </div>
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button @click="dialogFormVisible = false">取 消</el-button>
    <el-button type="primary" @click="closeDialog">确 定</el-button>
  </div>
</el-dialog>
</div>
</template>

组件script部分

1.变量数据区域

代码如下(示例):

<script>
export default {
  name: "UploadMany",
  data() {
    return {
      textarea:'',
      dialogImageUrl: '',
      dialogImgVisible: false,
      dialogVisible: false,
      fileList: [],
      imgs: [],
      images: [],
      UPLOAD_URL: "/v1/admin/common/upload",//这里填写你的后端上传接口地址
      authorToken: {
        Authorization: 'Bearer ' + sessionStorage.getItem("token"),
        siteId:sessionStorage.getItem("siteId")
      },
      param: {
        token: ''
      },
      fileNum: 0,
      num: 0,
      dialogFormVisible: false,//添加表单弹出框是否显示
      dialogChangeVisible: false,
      picsList: [],  //页面显示的数组
      // 防止重复提交
      loading: true,
    }
  },

2.方法区域

代码如下(示例):

methods: {
	//删除方法
    handleRemove(file) {
      console.log(file)
      // 1.获取将要删除的图片的临时路径
      const filePath = file.url
      // 2.从数组中,找到这个图片对应的索引值
      const i = this.imgs.findIndex((x) => x.url === filePath)
      // 3.调用数组的 splice 方法,把图片信息对象,从 pics 数组中移除
      this.imgs.splice(i, 1)
      console.log(this.imgs)
    },
    //预览方法
    handlePreview(file) {
      console.log(file);
      this.dialogImageUrl = file.url;
      this.dialogImgVisible = true;
    },
    //限制上传文件个数
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 10 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
    },
    //上传成功后
    handleSuccess(response, fileList) {
      console.log(response);
      console.log(fileList)
      this.loading = false
      if(response.code === 200){
        this.imgs.push({name: response.data.resourceName, url: response.data.resourceUrl, manyDescription: '', manyResourceId: response.data.id})
        this.num++;
        if(this.num == this.fileNum){
          for(let i = 0; i < this.num ; i++){
            this.$emit('getManyImg', this.imgs[i])
          }
          this.num = 0;
          this.fileNum = 0;
          this.images = this.imgs;
          this.imgs = [];
        }
      }else{
        this.$message.error('上传失败');
      }
    },
    
    handleBeforeUpload(file) {
      // 这里做可以做文件校验操作
      const isImg = /^image\/\w+$/i.test(file.type)
      if (!isImg && this.fileType == 'image/*') {
        this.$message.error('只能上传 JPG、PNG、GIF 格式!')
        return false
      }
      this.fileNum++;
    },

    uploadFile(){
      this.dialogFormVisible = true;
      this.loading = false;
    },
    
    closeDialog(){
      this.dialogFormVisible = false;
      this.imgs = [];
      this.images = [];
    }

  }
}

组件使用

1.在你需要用到的界面vue里导入组件

import UploadMany from '@/components/upload/UploadMany';
import {getToken} from '@/utils/auth';
export default {
  name: "TestEditor",
  components: {
    UploadMany,
  },

2.template部分使用组件

            <el-col :span="24">
              <el-form-item prop="manyImg" label="多图上传:" :label-width="imgWidth" class="form">
                <upload-many v-model="dialogForm.manyImg" @getManyImg="getManyImg" ></upload-many>
                <div class="fileList" style="margin-top: 10px;display: flex;flex-wrap: wrap;">
                  <div class="item" v-for="(itemPhoto,indexPhoto) in dialogForm.images" :key="indexPhoto">
                    <div class="item-left" style="position: relative">
                      <img :src="itemPhoto.url" alt="" :key="indexPhoto" class = "imgList">
                     <div class="item-bottom">
                       <div class="search-icon">
                         <i class="el-icon-search" @click="handlePreview(itemPhoto)"></i>
                       </div>
                       <div class="delete-icon">
                         <i class="el-icon-delete" @click="handleRemove(itemPhoto)"></i>
                       </div>
                     </div>
                    </div>
                    <el-input
                        type="textarea"
                        :autosize="{ minRows: 7, maxRows: 7}"
                        placeholder="请输入图片描述"
                        v-model="itemPhoto.manyDescription"
                        style=" width: 55%;height: 100%;margin-left: 10px">
                    </el-input>
                  </div>
                </div>
              </el-form-item>
            </el-col>

3.方法部分

    getManyImg(imgs) {
      this.dialogForm.images.push(imgs);
      console.log(this.dialogForm.images)
    },
        handleRemove(file) {
      console.log(file)
      // 1.获取将要删除的图片的临时路径
      const filePath = file.url
      // 2.从数组中,找到这个图片对应的索引值
      const i = this.dialogForm.images.findIndex((x) => x.url === filePath)
      // 3.调用数组的 splice 方法,把图片信息对象,从 pics 数组中移除
      this.dialogForm.images.splice(i, 1)
    },
    //预览图片
    handlePreview(file) {
      console.log(file);
      this.dialogImageUrl = file.url;
      this.dialogImgVisible = true;
    },

组件完整代码(含裁剪组件,不需要请手动删除)

<template>
<div>
    <div class="many">
      <el-form-item>
        <div class="upload-item">
          <el-button type="primary" @click="uploadFile">多图上传</el-button>
        </div>
      </el-form-item>
    </div>

  <!--裁剪弹窗-->
  <!-- vueCropper 剪裁图片实现-->
  <el-dialog title="图片剪裁" :visible.sync="dialogChangeVisible" append-to-body>
    <div class="cropper-content">
      <div class="cropper" style="text-align:center">
        <vueCropper
            ref="cropper"
            :img="option.img"
            :outputSize="option.size"
            :outputType="option.outputType"
            :info="true"
            :full="option.full"
            :canMove="option.canMove"
            :canMoveBox="option.canMoveBox"
            :original="option.original"
            :autoCrop="option.autoCrop"
            :fixed="option.fixed"
            :fixedNumber="option.fixedNumber"
            :centerBox="option.centerBox"
            :infoTrue="option.infoTrue"
            :fixedBox="option.fixedBox"
        ></vueCropper>
      </div>
    </div>
    <div slot="footer" class="dialog-footer">
      <el-button @click="dialogChangeVisible = false">取 消</el-button>
      <el-button type="primary" @click="finish" :loading="loading">确认</el-button>
    </div>
  </el-dialog>

  <el-dialog title="图片预览" :visible.sync="dialogImgVisible" width="50%">
    <img :src="dialogImageUrl" alt="" class="previewImg" />
  </el-dialog>


  <!--多图上传弹窗界面-->
<el-dialog :title="'上传'" :visible.sync="dialogFormVisible" custom-class="pub_dialog" >
  <el-form style="width: 750px;height: 380px">
    <!--内容部分  -->
    <el-form-item><!---->
        <div style="display: flex;justify-content: center">
          <label>选择文件:</label>
          <div>
            <div class="desc">支持 jpg, png 图片格式,且不超过500kb</div>
            <el-upload
                :action="UPLOAD_URL"
                :headers="authorToken"
                :auto-upload="true"
                accept="image/jpg,image/png,image/jpeg"
                :on-success="handleSuccess"
                :before-upload="handleBeforeUpload"
                :show-file-list="false"
                multiple
                :limit="10"
                :on-exceed="handleExceed"
                :file-list="fileList">
              <el-button size="small" type="primary">上传图片</el-button>
            </el-upload>
          </div>
        </div>

          <div class="fileList" style="margin-top: 10px;display: flex;flex-wrap: wrap;">
            <div class="item" v-for="(item,index) in images" :key="index">
              <img :src="item.url" alt="" :key="index" style=" width: 45%;height: 100%" class = "imgList">
              <div class="scissor-icon">
                <i class="el-icon-scissors" @click="changeFile(item)"></i>
              </div>
<!--                <div class="refresh-icon">-->
<!--                  <i class="el-icon-refresh" @click="handleRemove()"></i>-->
<!--                </div>-->
              <div class="delete-icon">
                <i class="el-icon-delete" @click="handleRemove(item)"></i>
              </div>
              <div class="search-icon">
                <i class="el-icon-search" @click="handlePreview(item)"></i>
              </div>
              <el-input
                  type="textarea"
                  :autosize="{ minRows: 7, maxRows: 7}"
                  placeholder="请输入图片描述"
                  v-model="item.manyDescription"
                  :key="index"
                  style=" width: 55%;height: 100%;margin-left: 10px">
              </el-input>
            </div>
          </div>
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button @click="dialogFormVisible = false">取 消</el-button>
    <el-button type="primary" @click="closeDialog">确 定</el-button>
  </div>
</el-dialog>
</div>
</template>
<script>
import VueCropper from 'vue-cropper'
import Vue from "vue";
Vue.use(VueCropper)
export default {
  name: "UploadMany",
  data() {
    return {
      textarea:'',
      dialogImageUrl: '',
      dialogImgVisible: false,
      dialogVisible: false,
      fileList: [],
      imgs: [],
      images: [],
      UPLOAD_URL: "/v1/admin/common/upload",
      authorToken: {
        Authorization: 'Bearer ' + sessionStorage.getItem("token"),
        siteId:sessionStorage.getItem("siteId")
      },
      param: {
        token: ''
      },
      fileNum: 0,
      num: 0,
      dialogFormVisible: false,//添加表单弹出框是否显示
      dialogChangeVisible: false,
      // 裁剪组件的基础配置option
      option: {
        img: '', // 裁剪图片的地址
        info: true, // 裁剪框的大小信息
        outputSize: 0.8, // 裁剪生成图片的质量
        outputType: 'jpeg', // 裁剪生成图片的格式
        canScale: false, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        // autoCropWidth: 300, // 默认生成截图框宽度
        // autoCropHeight: 200, // 默认生成截图框高度
        fixedBox: true, // 固定截图框大小 不允许改变
        fixed: true, // 是否开启截图框宽高固定比例
        fixedNumber: [7, 5], // 截图框的宽高比例
        full: true, // 是否输出原图比例的截图
        canMoveBox: false, // 截图框能否拖动
        original: false, // 上传图片按照原始比例渲染
        centerBox: false, // 截图框是否被限制在图片里面
        infoTrue: true // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
      },
      picsList: [],  //页面显示的数组
      // 防止重复提交
      loading: true,
    }
  },
  methods: {
    handleRemove(file) {
      console.log(file)
      // 1.获取将要删除的图片的临时路径
      const filePath = file.url
      // 2.从数组中,找到这个图片对应的索引值
      const i = this.imgs.findIndex((x) => x.url === filePath)
      // 3.调用数组的 splice 方法,把图片信息对象,从 pics 数组中移除
      this.imgs.splice(i, 1)
      console.log(this.imgs)
    },
    handlePreview(file) {
      console.log(file);
      this.dialogImageUrl = file.url;
      this.dialogImgVisible = true;
    },
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 10 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
    },
    handleSuccess(response, fileList) {
      console.log(response);
      console.log(fileList)
      this.loading = false
      if(response.code === 200){
        this.imgs.push({name: response.data.resourceName, url: response.data.resourceUrl, manyDescription: '', manyResourceId: response.data.id})
        this.num++;
        if(this.num == this.fileNum){
          for(let i = 0; i < this.num ; i++){
            this.$emit('getManyImg', this.imgs[i])
          }
          this.num = 0;
          this.fileNum = 0;
          this.images = this.imgs;
          this.imgs = [];
        }
      }else{
        this.$message.error('上传失败');
      }
    },
    // 裁剪按钮   限制图片大小
    changeFile(file) {
      console.log(file)
      this.option.img = file.url
      console.log(this.option.img)
      this.dialogChangeVisible = true
    },
    // 点击裁剪
    finish() {
      this.$refs.cropper.getCropBlob((data) => {
        console.log(data)
        console.log(data.size)
        this.$data.dialogChangeVisible = false
        this.axios.post("/v1/admin/common/upload",data).then((res) => {
          let code = res.data.code;
          if (code == 200) {
            this.$data.dialogFormVisible = false
            this.$message.success("上传成功");
          }
        }).catch((error) => {
          console.log(error);
        });
      })
    },
    handleBeforeUpload(file) {
      // 这里做可以做文件校验操作
      const isImg = /^image\/\w+$/i.test(file.type)
      if (!isImg && this.fileType == 'image/*') {
        this.$message.error('只能上传 JPG、PNG、GIF 格式!')
        return false
      }
      this.fileNum++;
    },

    uploadFile(){
      this.dialogFormVisible = true;
      this.loading = false;
    },
    closeDialog(){
      this.dialogFormVisible = false;
      this.imgs = [];
      this.images = [];
    }

  }
}
</script>
<style lang="scss" scoped>
.el-dialog{
  width: 50%;
}
.item {
  width: 300px;
  height: 140px;
  position: relative;
  display: flex;
  margin: 10px;

  .delete-icon {
    display: none;
  }
  .refresh-icon {
    display: none;
  }
  .search-icon {
    display: none;
  }
  .scissor-icon {
    display: none;
  }

  &:hover {
    .scissor-icon {
      display: block;
      position: absolute;
      width: 35px;
      height: 40px;
      line-height: 40px;
      left: 100px;
      top: 100px;
      background: rgba(59, 60, 61, 0.5);
      // box-sizing: content-box;
      z-index: 999;
      cursor: pointer;
      text-align: center;
      i {
        margin: 8px 10px 0 0;
        display: block;
        font-size: 24px;
        color: white;
      }
    }
    .delete-icon {
      display: block;
      position: absolute;
      width: 35px;
      height: 40px;
      left: 0px;
      top: 100px;
      background: rgba(59, 60, 61, 0.5);
      // box-sizing: content-box;
      z-index: 999;
      cursor: pointer;
      text-align: center;
      i {
        margin: 8px 10px 0 10px;
        display: block;
        font-size: 24px;
        color: white;
      }
    }
    .refresh-icon {
      display: block;
      position: absolute;
      width: 35px;
      height: 40px;
      left: 35px;
      top: 100px;
      background: rgba(59, 60, 61, 0.5);
      // box-sizing: content-box;
      z-index: 999;
      cursor: pointer;
      text-align: center;
      i {
        margin: 8px 10px 0 0;
        display: block;
        font-size: 24px;
        color: white;
      }
    }
    .search-icon {
      display: block;
      position: absolute;
      width: 65px;
      height: 40px;
      left: 35px;
      top: 100px;
      background: rgba(59, 60, 61, 0.5);
      // box-sizing: content-box;
      z-index: 999;
      cursor: pointer;
      text-align: center;
      i {
        margin: 8px 10px 0 10px;
        display: block;
        font-size: 24px;
        color: white;
      }
    }

  }
}
.imgList {
  border: 1px dashed #d9d9d9;
  border-radius: 5px;
  box-sizing: border-box;
  width: 180px;
  height: 180px;
  margin-top: 0px;
&:hover {
   border: 1px dashed #409eff;
 }
}

// 截图
.cropper-content {
  .cropper {
    width: auto;
    height: 300px;
  }
}

.previewImg {
  width: 50%;
  height: 100%
}
</style>

效果展示请添加图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值