oss-upload组件

/* ossUpload.js */
import OSS from 'ali-oss';
import Compressor from 'compressorjs';
import { randomString } from '@/utils/index.js';

const { accessKeyId, accessKeySecret, region, endpoint } = {
  region: 'oss-cn-hangzhou',
  accessKeyId: '',
  accessKeySecret: '',
  endpoint: 'oss-cn-hangzhou.aliyuncs.com'
};

const client = new OSS({
  // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: region,
  // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
  accessKeyId: accessKeyId,
  accessKeySecret: accessKeySecret,
  endpoint: endpoint,
  // 填写Bucket名称。
  bucket: 'xxx'
});
/**
 * 图片压缩
 */
function compressImage(fileList, backType, limitSize, quality) {
  const promiseAry = [];
  const maxSize = limitSize * 1024 * 1024;
  fileList.forEach(image => {
    promiseAry.push(new Promise((resolve, reject) => {
      if (image.size <= maxSize) { // 没操过限制,不用压缩
        resolve(image)
      }
      else {
        new Compressor(image, {
          // maxWidth: 750,
          // maxHeight: 750,
          quality: quality || 0.8,
          success(result) {
            let file = new File([result], image.name, { type: image.type })

            if (!backType || backType == 'blob') {
              resolve(result)
            } else if (backType == 'file') {
              resolve(file)
            } else {
              resolve(file)
            }
          },
          error(err) {
            console.log('图片压缩失败---->>>>>', err)
            resolve(image)
          }
        })
      }
    }))
  })
  return Promise.all(promiseAry)
}

const defaultLimit = 1;
/**
 *
 * @param fileList 上传图片的资源路径
 * @param dir oss要保存的文件夹
 * @param limitSize oss图片限制 默认1m 0为不限制
 * @returns {OSS文件路径}
 */

async function uploadOSS(fileList, dir = 'file', {
  limitSize = defaultLimit, compress = false
}) {
  return new Promise((resolve, reject) => {
    const promiseAry = [];
    let randomVal, randomStr, imgtype, fileName, tmpAry, maxSize = limitSize * 1024 * 1024;
    let _Promise = compress ? compressImage(fileList, 'file', limitSize) : Promise.resolve(fileList)

    if (compress) {
      console.log('压缩前的图片列表', fileList)
    }
    _Promise.then(fileList => {
      if (compress) {
        console.log('压缩后的图片列表', fileList)
      }
      const canUploadList = limitSize == 0 ? fileList : fileList.filter(file => file.size <= maxSize);
      canUploadList.forEach(file => {

        tmpAry = file.name.split('.');
        imgtype = tmpAry[tmpAry.length - 1]
        randomVal = +new Date();
        randomStr = randomString()
        fileName = `${randomVal}_${randomStr}.${imgtype}`
        promiseAry.push(client.put(`${dir}/${fileName}`, file, {
          headers: {
            'aa': 'aa'
          }
        }))
      })
      Promise.all(promiseAry).then(result => {
        let code = canUploadList.length == fileList.length ? 1 : 0
        resolve({
          result,
          code,
          msg: code == 1 ? '上传成功' : `${fileList.length == 1 ? '' : '部分'}图片大小超过${limitSize}M`
        });
      }).catch(e => {
        reject(e)
      })
    })

  });
}

export { uploadOSS, defaultLimit }
<template>
  <div>
    <div class="flex-wrap">
      <div class="oss-upload">
        <slot></slot>
        <label v-if="!disabled" class="hand">
          <input
            :multiple="multiple"
            type="file"
            class="hidden"
            @change="change"
          />
        </label>
      </div>
      <el-button
        v-if="!disabled && onDelete && value"
        @click="handleDelete"
        type="text"
        size="small"
        >删除</el-button
      >
    </div>
    <draggable
      class="drag-list"
      v-if="!disabled && showFileList && filelist.length > 0"
      v-model="filelist"
      @change="drag"
    >
      <div class="drag-item" v-for="(item, idx) in filelist" :key="idx">
        <img class="drag-item-img" :src="item" />
        <i class="el-icon-error" @click="remove(idx)"></i>
      </div>
    </draggable>
    <template v-else-if="showFileList && filelist.length > 0">
      <div class="drag-list">
        <div class="drag-item" v-for="(item, idx) in filelist" :key="idx">
          <img class="drag-item-img" :src="item" />
        </div>
      </div>
    </template>
  </div>
</template>

<script>
import draggable from "vuedraggable";
import { uploadOSS, defaultLimit } from "@/utils/ossUpload";
export default {
  components: {
    draggable,
  },
  props: {
    value: String,
    limit: [String, Number],
    disabled: {
      type: Boolean,
      default: false,
    },
    compress: {
      type: Boolean,
      default: false,
    },
    showUploadResult: {
      type: Boolean,
      default: true,
    },
    multiple: {
      type: Boolean,
      default: false,
    },
    showFileList: {
      type: Boolean,
      default: false,
    },
    fileList: {
      type: Array,
      default: () => [],
    },
    onBeforeUpload: {
      type: Function,
      default: () => {},
    },
    onSuccess: {
      type: Function,
      default: () => {},
    },
    onError: {
      type: Function,
      default: () => {},
    },
    onChange: {
      type: Function,
      default: () => {},
    },
    onDelete: {
      type: Function,
      default: null,
    },
    dir: {
      type: String,
      default: "file",
    },
  },
  watch: {
    fileList: {
      handler(val) {
        this.filelist = val || [];
      },
      immediate: true,
    },
  },
  data() {
    return {
      filelist: [],
    };
  },
  methods: {
    clearFileList() {
      this.filelist = [];
    },
    handleDelete() {
      this.onDelete && this.onDelete();
    },
    remove(index) {
      this.filelist = this.filelist.filter((item, idx) => idx !== index);
      this.onChange(this.filelist);
    },
    drag() {
      this.onChange(this.filelist);
    },
    change(e) {
      const files = Array.from(e.target.files);
      const limit = Number(this.limit);
      // 限制图片类型
      const _files = files.filter((d) => {
        if (d.type == "image/png" || d.type == "image/jpeg") {
          return true;
        } else {
          return false;
        }
      });
      e.target.value = null;

      // 存在不符合的图片类型
      if (_files.length !== files.length) {
        this.$message.warning("图片类型不是png或者jpeg");
      }
      // 没有有效的图片直接返回
      if (_files.length === 0) {
        return;
      }
      this.onBeforeUpload(); // 上传前钩子
      uploadOSS(_files, this.dir, {
        limitSize: isNaN(limit) ? defaultLimit : limit,
        compress: this.compress,
      })
        .then(({ result, code, msg }) => {
          this.showUploadResult &&
            this.$message({
              type: code == 1 ? "success" : "warning",
              message: msg,
            });
          result.forEach((res) => {
            this.filelist.push(res.url);
          });

          if (this.multiple || this.filelist[this.filelist.length - 1]) {
            this.onSuccess(
              result,
              this.multiple
                ? this.filelist
                : this.filelist[this.filelist.length - 1]
            );
          }
        })
        .catch((err) => {
          console.error(err);
          this.onError(err);
        });
    },
  },
};
</script>

<style scoped>
.oss-upload img {
  display: block;
}
.flex-wrap {
  display: inline-flex;
  align-items: center;
}
.oss-upload {
  display: inline-block;
  position: relative;
  margin-right: 10px;
}
.hand {
  z-index: 99;
  cursor: pointer;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
.hidden {
  display: none;
}

.el-icon-error {
  position: absolute;
  right: -7px;
  top: -7px;
  font-size: 18px;
  cursor: pointer;
  color: #f56c6c;
}
.drag-list {
  display: flex;
  flex-wrap: wrap;
  padding: 20px 0;
}
.drag-item {
  position: relative;
  margin-right: 10px;
}

.drag-item-img {
  object-fit: contain;
  width: 100px;
  height: 100px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
</style>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容