vue 2.0 elemnt ui + vue-cropper 实现单图裁剪上传

1.安装

npm install vue-cropper

2.在任意地方创建一个cropper.vue 组件

<template>

  <div>

    <div class="cropper-content">

      <!-- 剪裁框 -->

      <div class="cropper">

        <vueCropper ref="cropper" :img="option.img" :outputSize="option.size" :outputType="option.outputType" :info="true" :full="option.full" :centerBox="option.centerBox" :canMove="option.canMove" :canMoveBox="option.canMoveBox" :original="option.original" :autoCrop="option.autoCrop" :autoCropWidth="option.autoCropWidth" :autoCropHeight="option.autoCropHeight" :fixedBox="option.fixedBox" @realTime="realTime" :fixed="option.fixed" :fixedNumber="fixedNumber"></vueCropper>

        <!-- <vueCropper ref="cropper" :img="option.img" :outputSize="option.size" :outputType="option.outputType"></vueCropper> -->

      </div>

      <!-- 预览框 -->

      <div class="show-preview" :style="{'width': '500px', 'height': '400px',  'overflow': 'hidden', 'margin': '0 25px', 'display':'flex', 'align-items' : 'center'}">

        <div :style="previews.div" class="preview">

          <img :src="previews.url" :style="previews.img">

        </div>

      </div>

    </div>

    <div class="footer-btn">

      <!-- 缩放旋转按钮 -->

      <div class="scope-btn">

        <el-button type="primary" icon="el-icon-zoom-in" @click="changeScale(1)"></el-button>

        <el-button type="primary" icon="el-icon-zoom-out" @click="changeScale(-1)"></el-button>

          <el-button type="primary" @click="rotateRight">顺时针旋转</el-button>

        <el-button type="primary" @click="rotateLeft">逆时针旋转</el-button>

      </div>

      <!-- 确认上传按钮 -->

      <div class="upload-btn">

        <!-- <el-button type="primary" @click="uploadImg('blob')">上传</el-button> -->

        <el-button type="primary" :disabled="isDisabled" @click="uploadImg('base64')">上传</el-button>

      </div>

    </div>

  </div>

</template>

<script>

import { VueCropper } from 'vue-cropper';

// console.log(VueCropper);

export default {

  data () {

    return {

      previews: {}, // 预览数据

      option: {

        img: '', // 裁剪图片的地址  (默认:空)

        outputSize: 1, // 裁剪生成图片的质量  (默认:1)

        full: false, // 是否输出原图比例的截图 选true生成的图片会非常大  (默认:false)

        outputType: 'jpg', // 裁剪生成图片的格式  (默认:jpg)

        canMove: true, // 上传图片是否可以移动  (默认:true)

        original: false, // 上传图片按照原始比例渲染  (默认:false)

        canMoveBox: true, // 截图框能否拖动  (默认:true)

         centerBox: true, // 截图框是否被限制在图片里面

        autoCrop: true, // 是否默认生成截图框  (默认:false)

        autoCropWidth: 500, // 默认生成截图框宽度  (默认:80%)

        autoCropHeight: 400, // 默认生成截图框高度  (默认:80%)

        fixedBox: false, // 固定截图框大小 不允许改变  (默认:false)

        fixed: false, // 是否开启截图框宽高固定比例  (默认:true)

        fixedNumber: [1.5, 1], // 截图框比例  (默认:[1:1])

        enlarge: 1

      },

      isDisabled: false,

      downImg: '#'

    };

  },

  props: ['imgFile', 'fixedNumber','autoCropWH',],

  methods: {

    changeScale (num) {

      // 图片缩放

      num = num || 1;

      this.$refs.cropper.changeScale(num);

    },

    rotateLeft () {

      // 向左旋转

      this.$refs.cropper.rotateLeft();

    },

    rotateRight () {

      // 向右旋转

      this.$refs.cropper.rotateRight();

    },

    Update () {

       this.option.autoCropWidth  = this.autoCropWH.w ? this.autoCropWH.w : 500

        this.option.autoCropHeight  = this.autoCropWH.h ? this.autoCropWH.h : 400

      this.option.img = this.imgFile.url;

    },

    realTime (data) {

      // 实时预览

      this.previews = data;

    },

    uploadImg (type) {

      // 将剪裁好的图片回传给父组件

      event.preventDefault();

      this.isDisabled = true;

      let that = this;

      if (type === 'blob') {

        this.$refs.cropper.getCropBlob(data => {

          that.$emit('upload', data);

        });

      } else {

        this.$refs.cropper.getCropData(data => {

          that.$emit('upload', data);

        });

      }

    }

  },

  components: { VueCropper }

};

</script>

<style>

.cropper-content {

  display: flex;

  display: -webkit-flex;

  justify-content: flex-end;

  -webkit-justify-content: flex-end;

}

.cropper-content .cropper {

  width: 500px;

  height: 400px;

}

.cropper-content .show-preview {

  flex: 1;

  -webkit-flex: 1;

  display: flex;

  display: -webkit-flex;

  justify-content: center;

  -webkit-justify-content: center;

  overflow: hidden;

  border: 1px solid #cccccc;

  background: #cccccc;

  margin-left: 40px;

}

.preview {

  overflow: hidden;

  border: 1px solid #cccccc;

  background: #cccccc;

}

.footer-btn {

  margin-top: 30px;

  display: flex;

  display: -webkit-flex;

  justify-content: flex-end;

  -webkit-justify-content: flex-end;

}

.footer-btn .scope-btn {

  width: 412px;

  display: flex;

  display: -webkit-flex;

  justify-content: space-between;

  -webkit-justify-content: space-between;

}

.footer-btn .upload-btn {

  flex: 1;

  -webkit-flex: 1;

  display: flex;

  display: -webkit-flex;

  justify-content: center;

  -webkit-justify-content: center;

}

.footer-btn .btn {

  outline: none;

  display: inline-block;

  line-height: 1;

  white-space: nowrap;

  cursor: pointer;

  -webkit-appearance: none;

  text-align: center;

  -webkit-box-sizing: border-box;

  box-sizing: border-box;

  outline: 0;

  margin: 0;

  -webkit-transition: 0.1s;

  transition: 0.1s;

  font-weight: 500;

  padding: 8px 15px;

  font-size: 12px;

  border-radius: 3px;

  color: #fff;

  background-color: #67c23a;

  border-color: #67c23a;

}

</style>

3.结合elemnt ui 使用组件

<template>

  <div>

       <el-upload

            :action="uploadUrl()"

            accept="image/png,image/jpg,image/jpeg"

            list-type="picture-card"

            :limit='1'

            :auto-upload="false"

            :on-preview="handlePictureCardPreview"

            :http-request="upload"

            :on-change="consoleFL"

            :file-list="uploadList"

            >

            <i class="el-icon-plus"></i>

            </el-upload>

            <el-dialog :visible.sync="dialogVisible">

            <img width="100%" :src="dialogImageUrl" alt="">

            </el-dialog>

            <!-- 剪裁组件弹窗 -->

            <el-dialog :visible.sync="cropperModel" width="1100px" :before-close="beforeClose">

            <Cropper :img-file="upfile" :autoCropWH='autoCropWH' ref="vueCropper" :fixedNumber="fixedNumber" @upload="upload">

            </Cropper>

            </el-dialog>

  </div>

</template>

<script>

import Cropper from '../../common/cropper';

import { showLoading, hideLoading,regular,Rodmo} from '../../../utils/loading.js'

  export default {

    data() {

      return {

        upfile: '', // 当前被选择的图片文件

        autoCropWH:{w:89,h:89},//裁剪的宽高

        uploadList:[], //图片显示列表

        fixedNumber: [1.5, 1],// 剪裁框比例设置

        dialogImageUrl: '', 

        dialogVisible: false,

        cropperModel: false, // 剪裁组件弹窗开关

      }

    },

     updated () {

        if (this.$refs.vueCropper) {

        this.$refs.vueCropper.Update();

        }

     },

    components: { //注册组件

        Cropper

    }, 

    methods: { 

        uploadUrl(){  //上传路径

         return '这里写自己的路径'

       },

         beforeClose () { //关闭弹窗

            this.cropperModel = false;

            },

       consoleFL (file, fileList) {// 弹出剪裁框,将当前文件设置为文件

        this.cropperModel = true;

        this.upfile = file;

        },

      async upload (data) {  // 自定义upload事件

        let fileimg = ''

        fileimg = await this.base64ToFile(data,this.upfile.name)  //将base64图片转成文件类型

         if(fileimg != ''){

             let param = new FormData() 

             let imgurl = window.URL.createObjectURL(fileimg) //拿到截取的图片数据路径

          param.append('file',fileimg)  //添加FormData对象

          this.imgUpload(param,imgurl);

         }

    },

    handlePictureCardPreview(file) {  //点击文件列表中已上传的文件时

          this.dialogImageUrl = file.url;

          this.dialogVisible = true;

        },

    async imgUpload(formData,imgurl) { //自定义图片上传

          let url = this.uploadUrl()

        this.$axios.post(url,formData,{ headers: { 'Content-Type': 'multipart/form-data' } }).then(res => {

            setTimeout(function() {

                hideLoading()

            }, 200)

            if(!res.data.Code) {

                  let p = {}

                  p.url = imgurl 

                  this.uploadList = [p]  //将截取的图片数据路径赋值给显示数组

                   this.$refs.vueCropper.isDisabled = false;

                   this.$message({ message: res.data.Msg, type: 'success' }); //elemnt ui成功提示

            } else {

                this.$alert(res.data.Msg, '错误提醒', {

                    confirmButtonText: '确定',

                    callback: action => {

                        }

                    });

                }

            })   

             this.cropperModel = false;  //关掉弹窗

        },

  base64ToFile(urlData, fileName) { //将base64转换为file

        let arr = urlData.split(',');

        let mime = arr[0].match(/:(.*?);/)[1];

        let bytes = atob(arr[1]); // 解码base64

        let n = bytes.length

        let ia = new Uint8Array(n);

        while (n--) {

            ia[n] = bytes.charCodeAt(n);

        }

        return new File([ia], fileName, { type: mime });

    },

    }, 

  }

</script>

<style>

</style>

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