vue使用 vue-cropper插件封裝圖片裁剪等功能

安裝vue-cropper

npm install vue-cropper

 在.vue的文件中引入:

    <template>
      <div class="hello">
          <div style="width:600px;height:600px;">
            <vueCropper
            ref="cropper"
            :img="option.img"
            :outputSize="option.outputSize"
            :outputType="option.outputType"
            :info="true"
            :full="option.full"
            :canMove="option.canMove"
            :canMoveBox="option.canMoveBox"
            :fixedBox="option.fixedBox"
            :original="option.original"
            :autoCrop="option.autoCrop"
            :autoCropWidth="option.autoCropWidth"
            :autoCropHeight="option.autoCropHeight"
            :centerBox="option.centerBox"
            :high="option.high"
            :infoTrue="option.infoTrue"
            :enlarge="option.enlarge"
            @realTime="realTime"
            @imgLoad="imgLoad"
            @cropMoving="cropMoving"></vueCropper>
        </div>     
    </div>
</template>
  
<script>
import { VueCropper }  from 'vue-cropper' 
export default {
  name: 'HelloWorld',
  components:{VueCropper},
  data () {
    return {
     
    }
  },
  methods:{

  }
}
</script>

在main.js中全局引入:

/*裁剪*/
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)

 

封裝一個圖片增強的組件,可實現圖片的縮放、旋轉、裁剪等功能,效果如下:

                                                              

 

 調用組件的代碼: 

<!--組件調用示例-->
<template>
  <div>
    <div   style="    margin-left: 20px;margin-top: 20px; ">
      <label>圖片上傳和圖片增強組件:</label>
      <img-cropper-comp @childEvent="getImgBase64"></img-cropper-comp>
    </div>

  </div>
</template>

<script>

  
  import ImgCropperComp from "../../components/imgcroppercompent/imgCropperComp";
   
  export default {
    name: 'home',
    components: { ImgCropperComp },
    data() {
      return {
      }
    },
    computed: {},
    created() {

    },
    methods: {
      //接受子組件傳遞的參數
      getImgBase64(param) {
        console.log('我是父組件base64:');
        console.log(param);
        this.img = param;
      }
    }
  }
</script>

組件結構:

 imgCropperComp.vue:

<!--選擇圖片加圖片裁剪-->
<template>
  <div class="peerUpload" style="margin-top: 20px;margin-left: 20px">
    <div class="upload">
      <el-upload
        class="self"
        drag
        action="test"
        :auto-upload="false"
        :on-change="onChange"
        :show-file-list="false"
      >
        <div class="_uploadImg" v-if="showUploadImg">
          <i class="el-icon-upload"></i>
          <div class="el-upload__text"><em>支持拖拽、點擊上傳</em></div>
          <div class="el-upload__tip" slot="tip">只能上傳jpg/png文件,且不超過500kb</div>
        </div>
        <img v-if="imageUrl" :src="imageUrl" style="width: 136px;height: 136px" class="avatar">
      </el-upload>
      <el-link v-if="imageUrl" type="primary" style="margin-left: 38px;" @click="cropImageDialog = true">圖片增強</el-link>
    </div>

     <!--圖片增強彈框組件-->
     <dialog-cropper-comp  :cropImageDialog="cropImageDialog" :fixedBox="fixedBox" :width="width" :imgFile="imageUrl" @childEvent="getChildValue"></dialog-cropper-comp>
  </div>
</template>

<script>
  import DialogCropperComp from "./dialogCropperComp";
  export default {
    name: "imgCropperComp",
    components: {DialogCropperComp},
    data() {
      return {
        showUploadImg: true,
        imageUrl: '',
        width: '43%',//增強圖片dialog寬度
        fixedBox: false,//是否固定裁剪框
        cropImageDialog: false//圖片增強dialog
      }
    },
    methods:{
      //獲取子組件傳遞的值
      getChildValue(param) {
        this.imageUrl = param;
        this.cropImageDialog = false;
        //獲得子組件的值並傳遞給父組件
        this.sendParamToParent();
      },
      //向父組件傳值
      sendParamToParent() {
        // 調用父組件的方法並傳遞參數
        this.$emit('childEvent', this.imageUrl)
      },
      //el-img
      onChange(file, fileList) {
        //blob類型
        // this.imageUrl = URL.createObjectURL(file.raw);
        this.showUploadImg = false;
        //轉base64
        let fr = new FileReader();
        fr.readAsDataURL(file.raw);
        fr.onload = e => {
          this.imageUrl = e.target.result;
          //值發生改變須向父組件傳值
          this.sendParamToParent();
        };
      }
    }
  }
</script>

<style>
  .self .el-upload-dragger {
    width: 136px;
    height: 136px;
  }

  .checkedClass .el-checkbox__label {
    width: 55px;
  }

  .checkedClass {
    margin-left: 12px;
  }
</style>
<style  lang="css"  scoped>
  .peerUpload {
    display: flex;
  }

  .upload {
    width: 136px;
    height: 136px;
  }


  .uploadBefore p {
    line-height: 28px;
    color: #cccccc;
    text-align: center;
    font-size: 14px;
  }

  .uploadAfter {
    width: 100%;
    height: 100%;
    overflow: hidden;
  }

</style>


dialogCropperComp.vue:

<!--圖片增強彈框組件-->
<template>
  <!--圖片裁剪-->
  <div class="personal">
    <!-- 上傳圖像前調整圖像的尺寸 -->
    <el-dialog title="圖片增強" :visible.sync="cropImageDialog" class="cropImageForm" :width="width"
               :close-on-click-modal="false"  :show-close="false">
      <div class="img-crop">
        <!-- 1.截圖區域 -->
        <div class="imgCrop-content">
          <div class="cropper-content">
            <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"
              :autoCropWidth="option.autoCropWidth"
              :autoCropHeight="option.autoCropHeight"
              :fixedBox="option.fixedBox"
              :centerBox="option.centerBox"
              @realTime="realTime"
              @imgLoad="imgLoad"
            ></vueCropper>
          </div>
          <div class="preview-content">
            <div class="show-preview">
              <div :style="previews.div" class="preview">
                <img :src="previews.url" :style="previews.img" />
              </div>
            </div>
            <p class="desc">預覽效果</p>
          </div>
        </div>
        <!-- 2.操作按鈕區域 -->
        <div class="btn-content">
          <input class="btn" type="button" value="+" title="放大" @click="changeScale(1)" />
          <input class="btn" type="button" style value="-" title="縮小" @click="changeScale(-1)" />
          <input class="btn" type="button" value="↺" title="左旋轉" @click="rotateLeft" />
          <input class="btn" type="button" value="↻" title="右旋轉" @click="rotateRight" />
          <input class="btn" type="button" value="[]" title="框選" @click="changeLayer" />
          <input v-if="false" class="btn" type="button" value="↓" title="下載" @click="down('blob')" />
        </div>
      </div>
      <div class="btn-footer">
        <el-button @click="sendParamToParent" size="small">關閉</el-button>
        <el-button type="primary" @click="submitPhoto" size="small">確定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
  import { VueCropper } from "vue-cropper";
    export default {
      name: "dialogCropperComp",
      components: {
        VueCropper
      },
      props: ['cropImageDialog', 'fixedBox','width','imgFile'],
      data() {
        return {
          imageUrl: '',
          //剪切圖片上傳
          previews: {},
          option: {
            img: "",// 裁剪圖片的地址
            outputSize: 1, //剪切後的圖片質量(0.1-1)
            full: false, //輸出原圖比例截圖 props名full
            outputType: "png",// 裁剪生成圖片的格式
            canMove: true,
            original: false,// 上傳圖片按照原始比例渲染
            canMoveBox: true,// 截圖框能否拖動
            autoCrop: false, // 是否默認生成截圖框
            autoCropWidth: 150,
            autoCropHeight: 150,
            fixedBox: true,// 固定截圖框大小 不允許改變

            info: true, // 裁剪框的大小信息
            canScale: false, // 圖片是否允許滾輪縮放
            fixed: true, // 是否開啓截圖框寬高固定比例
            fixedNumber: [7, 5], // 截圖框的寬高比例
            centerBox: true, // 截圖框是否被限制在圖片裏面
            infoTrue: true // true 爲展示真實輸出圖片寬高 false 展示看到的截圖框寬高
          },
        }
      },
      watch: {
        imgFile: {
          handler(newImgFile, oldImgFile) {
            this.option.img = newImgFile;
            this.imageUrl = newImgFile;
          },
          immediate: true
        },
        fixedBox: {
          handler(newValue, oldValue) {
            this.option.fixedBox = newValue;
          },
          immediate: true
        },
      },
      methods:{
        sendParamToParent() {
          // 調用父組件的方法並傳遞參數
          this.$emit('childEvent', this.imageUrl)
        },
        // 上傳圖像
        submitPhoto() {
          // 獲取截圖的base64 數據
          this.$refs.cropper.getCropData(data => {
            this.imageUrl = data;
            this.sendParamToParent();



            //console.log("壓縮前的圖片大小:" + data.length)
            // let img = new Image(),
            //   _this = this
            // img.src = data
            // img.onload = function() {
            //   // let _data = _this.compress(img)
            //   let blob = _this.dataURItoBlob(data)
            //   let formData = new FormData()
            //   formData.append("icon", blob)
            //   //console.log("將blob對象轉成formData對象:" + formData.get("icon"))
            // }
          });
          // 獲取截圖的blob數據
          // this.$refs.cropper.getCropBlob((data) => {
          //   // do something
          //   console.log(data)
          // })
        },
        /*圖片操作欄開始*/
        //放大/縮小
        changeScale(num) {
          num = num || 1;
          this.$refs.cropper.changeScale(num);
        },
        //左旋轉
        rotateLeft() {
          this.$refs.cropper.rotateLeft();
        },
        //右旋轉
        rotateRight() {
          this.$refs.cropper.rotateRight();
        },
        changeLayer() {
          this.option.autoCrop = !this.option.autoCrop;
          if (!this.option.autoCrop) {
            // this.$refs.cropper.startCrop() 開始截圖
            // this.$refs.cropper.stopCrop() 停止截圖
            this.$refs.cropper.clearCrop() //清除截圖
            // this.$refs.cropper.changeScale() 修改圖片大小 正數爲變大 負數變小
            // this.$refs.cropper.getImgAxis() 獲取圖片基於容器的座標點
            // this.$refs.cropper.getCropAxis() 獲取截圖框基於容器的座標點
            // this.$refs.cropper.goAutoCrop 自動生成截圖框函數
            // this.$refs.cropper.rotateRight() 向右邊旋轉90度
            // this.$refs.cropper.rotateLeft() 向左邊旋轉90度
          }
        },
        // 實時預覽函數
        realTime(data) {
          this.previews = data;
        },
        //下載圖片
        down(type) {
          var aLink = document.createElement("a");
          aLink.download = "author-img";
          if (type === "blob") {
            this.$refs.cropper.getCropBlob(data => {
              aLink.href = window.URL.createObjectURL(data);
              aLink.click();
            });
          } else {
            this.$refs.cropper.getCropData(data => {
              aLink.href = data;
              aLink.click();
            });
          }
        },
        imgLoad(msg) {
          console.log("imgLoad");
          console.log(msg);
        },
        /*圖片操作欄結束*/

        // 壓縮圖片
        compress(img) {
          let canvas = document.createElement("canvas"),
            ctx = canvas.getContext("2d"),
            initSize = img.src.length,
            width = img.width,
            height = img.height;
          canvas.width = width
          canvas.height = height
          // 鋪底色
          ctx.fillStyle = "#fff"
          ctx.fillRect(0, 0, canvas.width, canvas.height)
          ctx.drawImage(img, 0, 0, width, height)
          //進行壓縮
          let ndata = canvas.toDataURL("image/jpeg", 0.8)
          //console.log("壓縮後的圖片大小:" + ndata.length)
          return ndata
        },
        // base64轉成bolb對象
        dataURItoBlob(base64Data) {
          let byteString
          if (base64Data.split(",")[0].indexOf("base64") >= 0)
            byteString = atob(base64Data.split(",")[1])
          else
            byteString = unescape(base64Data.split(",")[1])
          let mimeString = base64Data .split(",")[0] .split(":")[1] .split(";")[0];
          let ia = new Uint8Array(byteString.length);
          for (let i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
          }
          return new Blob([ia], { type: mimeString })
        },
      }
    }
</script>
<style lang="less" >
  .personal {
    margin: 10px 0;
    padding: 10px;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    overflow-y: hidden;
    border-radius: 3px;
    padding-bottom: 20px;
    .content {
      background-color: #fff;
      width: 100%;
      height: 100%;
      border-radius: 6px;
      padding: 10px;
      // overflow-y: scroll;
      overflow: hidden;
      display: flex;
      padding: 10px 0;
      flex-direction: column;
      //  1.標題及圖像說明
      .content-desc {
        margin: 0px 10px;
        .title {
          font-size: 16px;
          border-left: 5px solid #2d8cf0;
          padding-left: 10px;
          margin-bottom: 16px;
        }
        .desc {
          margin-left: 18px;
        }
      }
      // 2.圖像區域
      .content-image {
        display: flex;
        justify-content: rows;
        margin: 20px 30px;
        li {
          width: 180px;
          height: 180px;
          margin-right: 20px;
          position: relative;
          .delete-img {
            display: none;
          }
          &:hover {
            .delete-img {
              display: block;
              position: absolute;
              width: 180px;
              height: 40px;
              line-height: 40px;
              left: 0px;
              top: 140px;
              background: rgba(59, 60, 61, 0.5);
              // box-sizing: content-box;
              z-index: 999;
              cursor: pointer;
              text-align: right;
              i {
                margin: 8px 10px 0 0;
                display: block;
                font-size: 24px;
                color: white;
              }
            }
          }
        }
        img {
          width: 180px;
          height: 180px;
          border-radius: 4px;
        }
        .upload-img:hover {
          border: 1px dashed #92cccc;
        }
      }
    }
    // 裁剪圖像對話框
    .cropImageForm {
      .img-crop {
        // 1.截圖區域
        .imgCrop-content {
          margin: 0 20px;
          display: flex;
          display: -webkit-flex;
          justify-content: flex-start;
          -webkit-justify-content: flex-start;
          .cropper-content {
            width: 350px;
            height: 350px;
            margin-right: 40px;
          }
          .preview-content {
            .show-preview {
              // border: 1px solid #ccc;
              box-sizing: border-box;
              width: 150px;
              height: 150px;
              overflow: hidden;
              flex: 1;
              -webkit-flex: 1;
              display: flex;
              display: -webkit-flex;
              justify-content: center;
              -webkit-justify-content: center;
              .preview {
                overflow: hidden;
                /*border-radius: 50%;*/
                /*border: 1px solid #cccccc;*/
                background: #fff;
                margin-left: 0px;
              }
            }
            .desc {
              margin-top: 10px;
              text-align: center;
            }
            .el-button {
              margin: 10px 40px;
            }
          }
        }
        // 2.操作按鈕區域
        .btn-content {
          width: 350px;
          margin: 10px 20px;
          text-align: center;
          // #uploads {
          //   position: absolute;
          //   clip: rect(0 0 0 0);
          // }
          .btn {
            height: 32px;
            width: 32px;
            font-size: 20px;
            margin: 3px 5px;
            background-color: #fff;
            border: 1px solid #999;
            border-radius: 4px;
          }
        }
      }
      .btn-footer {
        width: 100%;
        text-align: right;
        padding-right: 20px;
        margin-top: -20px;
      }
    }
  }
</style>

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章