1、使用van-uploader 

   使用van-uploader组件上传图片,并将其封装成组件,接收传入的参数imglist。图片地址为服务器返回的。

完整代码

<template>
  <div class="image-uploader">
    <div class="list-img" v-for="(src, srcKey) in list" :key="srcKey">
      <van-image
        :src="src"
        width="2.133rem"
        height="2.133rem"
        @click="previewImage(src, srcKey)"
      >
        <template v-slot:loading>
          <van-loading type="spinner" size="20" />
        </template>
        <van-icon
          name="cross"
          size="6"
          class="del-icon"
          color="#fff"
          @click="onDelImage(srcKey)"
        />
      </van-image>
    </div>
    <div class="loading" v-if="isShowLoading">
      <div class="loading-icon">
      </div>
      <div class="loading-text">正在上传</div>
    </div>

    <van-uploader
      class="list-upload"
      :after-read="afterRead"
      accept="image/*"
      :preview-image="false"
      multiple
    />

  </div>
</template>
<script>
import Compressor from 'compressorjs';
import { ImagePreview, Toast } from 'vant';
import { mapGetters } from "vuex";
import { multipleFiles } from '@/api/work';
export default {
  props: {
    imglist: Array,
  },
  data() {
    return {
      list: [],
      isShowLoading: false,
    }
  },
  computed: {
    ...mapGetters([
      "HOST"
    ]),
  },
  watch: {
    imglist() {
      this.list = this.imglist
    },
  },
  mounted() {
    this.list = this.imglist;
  },
  methods: {
    beforeRead(file) {
      return new Promise((resolve) => {
        // compressorjs 默认开启 checkOrientation 选项
        // 会将图片修正为正确方向
        new Compressor(file, {
          success: resolve,
          error(err) {
            console.log(err.message);
          },
        });
      });
    },
    afterRead(file) {
      console.log("afterRead", file)
      this.isShowLoading = true;
      // 多文件上传
      //   let _this = this;
      var formData = new FormData();
      if (file.constructor != Array) {
        formData.append("file", file.file);
      } else {
        file.forEach(element => {
          formData.append("file", element.file);
        });
      }
      multipleFiles(formData).then((res) => {
        if (res.data.code == 20000) {
          file.status = 'done';
          file.message = '';
          let list = res.data.data;
          list.forEach(element => {
            let url = this.HOST + element.afterName;
            this.list.push(url);
          });
          console.log("上传后", this.list)
        }
      }).finally(() => {
        this.isShowLoading = false;
      });
    },

    previewImage(url, urlKey) {
      ImagePreview({
        // 真实数据
        images: this.list,
        showIndex: true,
        loop: true,
        startPosition: urlKey
      });
    },

    //删除图片
    onDelImage(index) {
      this.list.splice(index, 1);
    },
  }
}
</script>
<style lang="scss" scoped>
.image-uploader {
  width: 100%;
  border: 1px dashed rgb(220 223 230);
  display: flex;
  flex-wrap: wrap;
  .list-img {
    position: relative;
    margin: 5px;
  }
  .del-icon {
    position: absolute;
    top: 0;
    right: 0;
    width: 16px;
    height: 16px;
    text-align: right;
    background-color: rgb(0 0 0 / 70%);
    border-radius: 0 0 0 12px;
  }
  .list-upload {
    margin: 5px;
  }
}
.loading {
  margin: 5px;
  width: 80px;
  height: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #c6c7c9;
  background: rgb(247 248 250);
  margin-right: 5px;
  animation-duration: 2s;
  .loading-text {
    margin-top: 6px;
  }
}
.loading-icon {
  width: 50px;
  height: 50px;
  margin: 0 auto;
  background-color: #f7f8fa;
}
</style>

 主要代码

1、添加正在上传的提示

在图片上传和image显示上传的图片间会存在等待时间,因此加了一个下图所示的正在上传,在调用上传的方法是显示样式,图片接收成功后隐藏样式。(本来还想加一个loading加载的动态效果,奈何太菜没有搞出来)

<div class="loading" v-if="isShowLoading">
   <div class="loading-icon">
   </div>
   <div class="loading-text">正在上传</div>
</div>

2、实现多文件上传(multiple)

官方文档:Vant 2 - Mobile UI Components built on Vue

afterRead(file) {
      console.log("afterRead", file)
      this.isShowLoading = true;
      let _this = this;
      var formData = new FormData();
      if (file.constructor != Array) {
        formData.append("file", file.file);
      } else {
        file.forEach(element => {
          formData.append("file", element.file);
        });
      }
      multipleFiles(formData).then((res) => {
        if (res.data.code == 20000) {
          let list = res.data.data;
          list.forEach(element => {
            let url = this.HOST + element.afterName;//根据返回值拼接成需要的图片地址
            _this.list.push(url);
          });
          console.log("上传后", this.list)
        }
      }).finally(() => {
        this.isShowLoading = false;
      });
    },

 开启图片多选功能后,打印一下file值

选择一张图片上传,file值如下图所示,返回值是一个对象

 选择两个图片上传,file值是一个数组

因为上传一个图片和多个图片,file的值类型不同,所以在转FormData前先判断一下file是不是数组,如果是数组就用foreach循环

if (file.constructor != Array) {
  formData.append("file", file.file);
} else {
  file.forEach(element => {
     formData.append("file", element.file);
  });
}

2、使用原生input 

 1、用input代替van-uploader

  <div class="uploader_box list-upload">
      <input
        type="file"
        id="logimg"
        accept="image/*"
        multiple="multiple"
        @change="change($event)"
      />
      <van-icon class="camera-icon" name="photograph" />
  </div> 

2、上传文件的方法

   change(e) {
      if (e.target.files.length > 0) {
        this.getUrl(e.target.files); //多文件上传
      }
    },
    getUrl(file) {
      console.log("getUrl", file)
      this.isShowLoading = true;

      // 多文件上传
      let _this = this;
      var formData = new FormData();
      // file.forEach无效,使用for( ; ; ;)循环
      for (let i = 0; i < file.length; i++) {
        formData.append("file", file[i]);
      }
      let config = {
        headers: {
          "Content-Type": "multipart/form-data"
        }
      };
      multipleFiles(formData, config).then((res) => {
        if (res.data.code == 20000) {
          file.status = 'done';
          file.message = '';
          let list = res.data.data;
          list.forEach(element => {
            let url = this.HOST + element.afterName;
            _this.list.push(url);
          });
        }
      }).catch(error => {
        Toast.fail("上传文件接口调用失败")
      }).finally(() => {
        this.isShowLoading = false;
      });
    },

 上传一个文件时,file的返回值

 上传两个文件值,file的返回值

  返回值都是一个object对象,就直接使用foreach将文件转成FormData。

3、实现一个跟van-uploader相同的样式

.uploader_box {
  width: 80px;
  height: 80px;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  box-sizing: border-box;
  margin: 0 8px 8px 0;
  // border: 1px dashed rgb(220 223 230);
  background-color: rgb(247 248 250);
  #logimg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
  }
  .camera-icon {
    color: rgb(220 222 224);
    font-size: 24px;
  }
}

样式实现效果:

 3、在文件中引入组件

<div style="padding: 5px 10px 0 10px">
   <p style="color: #646566">答案补充:</p>
   <uploader :imglist="data.topic.topicResult.imgSrc" />
</div>

提示:如果出现部分图片能上传,部分图片不能上传,可以看看是不是服务器上设置了图片的大小。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐