天天看點

Vue圖檔上傳壓縮(放大左右滑動)

Vue圖檔上傳壓縮(放大左右滑動)

描述: 早在17年入行的時候就有需求做圖檔上傳,其實很簡單幾個步驟就可以搞定
  • 備注: 樣式采用計算px轉rem
  • 主要效果
    Vue圖檔上傳壓縮(放大左右滑動)
    Vue圖檔上傳壓縮(放大左右滑動)
    Vue圖檔上傳壓縮(放大左右滑動)

主要步驟

檔案上傳

圖檔壓縮

放大滑動

  • 涉及input,canvas,swiper
dom
<template>
  <!--輪播-->
  <div class="upload">
    <div class="upload_img">
      <div class="img_list" v-for="(item, index) in imgList" :key="index" @click="scaleLargeSwiper(index)">
        <img class="img_close" src="../../../assets/image/common/close.png" @click="delImg(index, $event)">
        <img class="img" :src="item">
      </div>
      <div class="img_list upload_line" v-if="imgList.length < maxImgLength">
        <span>+</span>
        <input ref="input" type="file" name="file" accept="image/*" multiple="multiple" @input="handleFileChange">
      </div>
    </div>
    <!--輪播-->
    <swiper v-if="isShowSwiper"
            @closeModel="closeModel"
            :imgList="imgList"
            :defaultIndex="defaultIndex"></swiper>
  </div>
</template>

           
js
<script>
import swiper from "./swiper";
export default {
  name: "upload",
  components: {swiper},
  props: {
    // 按鈕文字
    btnTitle: {
      default: '',
      type: String
    },
    // 最大圖檔數
    maxImgLength: {
      default: 5,
      type: Number
    },
    // 預設已有圖檔
    outImgList: {
      type: Array,
      default() {
        return []
      }
    },
    // 最大上傳
    maxSize: {
      default: 2,
      type: Number
    },
    text: {
      default: ''
    }
  },
  data(){
    return {
      // 圖檔最大寬度
      maxWidth: 1000,
      // 圖檔最大高度
      maxHeight: 1000,
      // 圖檔集合
      imgList: [],
      // 是否顯示輪播
      isShowSwiper: false,
      // 預設顯示索引
      defaultIndex: 0,
      // 顯示loading
      isLoading: false
    }
  },
  created() {
    this.imgList = [...this.outImgList]
  },
  methods: {
    // 選擇圖檔處理
    handleFileChange() {
      let files = this.$refs.input.files
      let size,
        len = files.length > this.maxImgLength ? this.maxImgLength : files.length
      for (let i = 0; i < len; i++) {
        size = files[i].size / 1024 / 1024
        let FR = new FileReader()
        FR.readAsDataURL(files[i]);
        FR.onload = (e) => {
          // 大于2M
          if (Math.floor(size) > 2) {
            this.checkImgSize(e.target.result)
          } else {
            this.imgList.push(e.target.result)
            this.$emit('addImg', this.imgList)
          }
        }
      }
    },
    // 校驗圖檔大小
    checkImgSize(url) {
      let img = new Image()
      img.src = url
      img.onload = () => {
        let { width: originW, height: originH } = img
        if (originW > this.maxWidth || originH > this.maxHeight) {
          if (originW > originH) {
            //寬大于高
            let rat = Math.ceil(originW / this.maxWidth),
             targetW = Math.floor(originW / rat), //目标的寬度
             targetH = Math.floor(originH / rat) //目标的高度
            this.imgPress(img, targetW, targetH )
          } else {
            //高大于寬
            Let rat = Math.ceil(originH / this.maxHeight),
             targetW= Math.floor(originW / rat),
             targetH = Math.floor(originH / rat)
            this.imgPress( img, targetW, targetH )
          }
        }
      }
    },
    // 圖檔壓縮
    imgPress(img, w, h) {
      let canvas = document.createElement('canvas’),
       ctx = canvas.getContext('2d’),
       anw = document.createAttribute('width’),
       anh = document.createAttribute('height')
      anw.nodeValue = w
      anh.nodeValue = h
      canvas.setAttributeNode(anw)
      canvas.setAttributeNode(anh)
      ctx.drawImage(img, 0, 0, w, h)
      let base64 = canvas.toDataURL('image/jpeg', 0.9)
      this.imgList.push(base64)
      this.$emit('addImg', this.imgList)
    },
    // 删除圖檔
    delImg(index, e) {
      e.stopPropagation()
      this.imgList.splice(index, 1)
      this.$refs.input && (this.$refs.input.value = null)
      this.$emit('delImg', this.imgList)
    },
    // 放大輪播
    scaleLargeSwiper(id) {
      this.isShowSwiper = true
      this.defaultIndex = id
    },
    // 關閉model
    closeModel(bool) {
      this.isShowSwiper = bool
    }
  }
}
</script>
> less
<style scoped lang="less">
// 上傳及描述
.upload {
  // 上傳圖檔
  .upload_img {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    .img_list {
      margin-top: 24px;
      width: 160px;
      height: 160px;
      overflow: hidden;
      margin-right: 20px;
      position: relative;
      .img_close {
        position: absolute;
        top: 0;
        right: 0;
        width: 34px;
        height: 34px;
      }
      .img {
        width: 160px;
        height: 160px;
        border-radius: 8px;
        display: block;
      }
    }
    .img_list:nth-child(3n) {
      margin-right: 0;
    }
  }
  .upload_line {
    border: 1px dashed #CCCCCC;
    border-radius: 8px;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
    input {
      width: 160px;
      height: 160px;
      position: absolute;
      opacity: 0;
    }
    span{
      color: #969798;
      font-size: 100px;
    }
  }
}
</style>
           
引用
<template>
	<section>
		<upload @addImg="addImg" @delImg="delImg"></upload>
	</section>
</template>

<script>
import upload from './common/upload'

export default {
  components: {upload},
data(){
	return {
		imgList: []
	}
},
  methods: {
	// 删除圖檔
delImg(imgList){
  this.imgList = imgList
},
// 新增圖檔
addImg(imgList){
  this.imgList = imgList
}

  }

}
</script>

           
整體來說還是比較容易實作簡單的圖檔上傳,此外你還可以做其他操作,比如放大之後的縮放,上傳之後base64轉Blob等

具體代碼具體見[ https://github.com/FrontWalker2000/self-vue-sys ]