vue项目图片裁剪上传——vue-cropper的使用,裁剪后上传头像

news2024/7/6 18:22:53

vue项目图片裁剪上传——vue-cropper的使用,裁剪后上传头像

npm地址:https://www.npmjs.com/package/vue-cropper

github地址:https://github.com/xyxiao001/vue-cropper

在线demo:http://github.xyxiao.cn/vue-cropper/example/

vue2-demo:https://codepen.io/xyxiao001/pen/wxwKGz

vue3-demo:https://codepen.io/xyxiao001/pen/yLooYKg

1、基本使用

1、安装

npm install vue-cropper
npm install vue-cropper --save-dev
yarn add vue-cropper
实例1

封装upload-cropper组件

<template>
  <div class="cropper-content">
    <div class="cropper-box">
      <div class="cropper">
        <vue-cropper
            ref="cropper"
            :img="option.img"
            :outputSize="option.outputSize"
            :outputType="option.outputType"
            :info="option.info"
            :canScale="option.canScale"
            :autoCrop="option.autoCrop"
            :autoCropWidth="option.autoCropWidth"
            :autoCropHeight="option.autoCropHeight"
            :fixed="option.fixed"
            :fixedNumber="option.fixedNumber"
            :full="option.full"
            :fixedBox="option.fixedBox"
            :canMove="option.canMove"
            :canMoveBox="option.canMoveBox"
            :original="option.original"
            :centerBox="option.centerBox"
            :height="option.height"
            :infoTrue="option.infoTrue"
            :maxImgSize="option.maxImgSize"
            :enlarge="option.enlarge"
            :mode="option.mode"
            @realTime="realTime"
            @imgLoad="imgLoad">
        </vue-cropper>
      </div>
      <!--底部操作工具按钮-->
      <div class="footer-btn">
        <div class="scope-btn">
          <label class="btn" for="uploads">选择封面</label>
          <input type="file" id="uploads" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" @change="selectImg($event)">
          <el-button size="mini" type="danger" plain icon="el-icon-zoom-in" @click="changeScale(1)">放大</el-button>
          <el-button size="mini" type="danger" plain icon="el-icon-zoom-out" @click="changeScale(-1)">缩小</el-button>
          <el-button size="mini" type="danger" plain @click="rotateLeft">↺ 左旋转</el-button>
          <el-button size="mini" type="danger" plain @click="rotateRight">↻ 右旋转</el-button>
        </div>
        <div class="upload-btn">
          <el-button size="mini" type="success" @click="uploadImg('blob')">上传封面 <i class="el-icon-upload"></i></el-button>
        </div>
      </div>
    </div>
    <!--预览效果图-->
    <div class="show-preview">
      <div :style="previews.div" class="preview">
        <img :src="previews.url" :style="previews.img">
      </div>
    </div>
  </div>
</template>
 
<script>
import { VueCropper } from 'vue-cropper'
export default {
  name: "CropperImage",
  components: {
    VueCropper
  },
  props:['Name'],
  data() {
    return {
      name:this.Name,
      previews: {},
      option:{
        img: '',             //裁剪图片的地址
        outputSize: 1,       //裁剪生成图片的质量(可选0.1 - 1)
        outputType: 'jpeg',  //裁剪生成图片的格式(jpeg || png || webp)
        info: true,          //图片大小信息
        canScale: true,      //图片是否允许滚轮缩放
        autoCrop: true,      //是否默认生成截图框
        autoCropWidth: 230,  //默认生成截图框宽度
        autoCropHeight: 150, //默认生成截图框高度
        fixed: true,         //是否开启截图框宽高固定比例
        fixedNumber: [1.53, 1], //截图框的宽高比例
        full: false,         //false按原比例裁切图片,不失真
        fixedBox: true,      //固定截图框大小,不允许改变
        canMove: false,      //上传图片是否可以移动
        canMoveBox: true,    //截图框能否拖动
        original: false,     //上传图片按照原始比例渲染
        centerBox: false,    //截图框是否被限制在图片里面
        height: true,        //是否按照设备的dpr 输出等比例图片
        infoTrue: false,     //true为展示真实输出图片宽高,false展示看到的截图框宽高
        maxImgSize: 3000,    //限制图片最大宽度和高度
        enlarge: 1,          //图片根据截图框输出比例倍数
        mode: '230px 150px'  //图片默认渲染方式
      }
    };
  },
  methods: {
    //初始化函数
    imgLoad (msg) {
      console.log("工具初始化函数====="+msg)
    },
    //图片缩放
    changeScale (num) {
      num = num || 1
      this.$refs.cropper.changeScale(num)
    },
    //向左旋转
    rotateLeft () {
      this.$refs.cropper.rotateLeft()
    },
    //向右旋转
    rotateRight () {
      this.$refs.cropper.rotateRight()
    },
    //实时预览函数
    realTime (data) {
      this.previews = data
    },
    //选择图片
    selectImg (e) {
      let file = e.target.files[0]
      if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
        this.$message({
          message: '图片类型要求:jpeg、jpg、png',
          type: "error"
        });
        return false
      }
      //转化为blob
      let reader = new FileReader()
      reader.onload = (e) => {
        let data
        if (typeof e.target.result === 'object') {
          data = window.URL.createObjectURL(new Blob([e.target.result]))
        } else {
          data = e.target.result
        }
        this.option.img = data
      }
      //转化为base64
      reader.readAsDataURL(file)
    },
    //上传图片
    uploadImg (type) {
      let _this = this;
      if (type === 'blob') {
        //获取截图的blob数据
        this.$refs.cropper.getCropBlob(async (data) => {
          let formData = new FormData();
          formData.append('file',data,"DX.jpg")
          //调用axios上传
          let {data: res} = await _this.$http.post('/api/file/imgUpload', formData)
          if(res.code === 200){
            _this.$message({
              message: res.msg,
              type: "success"
            });
            let data = res.data.replace('[','').replace(']','').split(',');
            let imgInfo = {
              name : _this.Name,
              url : data[0]
            };
            _this.$emit('uploadImgSuccess',imgInfo);
          }else {
            _this.$message({
              message: '文件服务异常,请联系管理员!',
              type: "error"
            });
          }
        })
      }
    },
  },
}
</script>
 
<style scoped>
.cropper-content{
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  }
   .cropper-box{
    flex: 1;
    width: 100%;
   }
    .cropper{
      width: auto;
      height: 300px;
    }
 
  .show-preview{
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
}
.preview{
      overflow: hidden;
      border:1px solid #67c23a;
      background: #cccccc;
    }
.footer-btn{
  margin-top: 30px;
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
}
  .upload-btn{
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
  }
  .scope-btn{
    display: flex;
    display: -webkit-flex;
    justify-content: space-between;
    padding-right: 10px;
  }
  .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;
    -webkit-transition: .1s;
    transition: .1s;
    font-weight: 500;
    padding: 8px 15px;
    font-size: 12px;
    border-radius: 3px;
    color: #fff;
    background-color: #409EFF;
    border-color: #409EFF;
    margin-right: 10px;
  }
</style>

新建upload-cropper

<template>
  <div class="cropper-app">
    <el-form :model="formValidate" :rules="ruleValidate" ref="formValidate" label-width="100px" class="demo-ruleForm">
      <el-form-item label="封面上传" prop="mainImage">
        <div class="list-img-box">
          <div v-if="formValidate.mainImage !== ''">
            <img :src="formValidate.mainImage" style='width:300px;height:150px' alt="自定义封面">
          </div>
          <div v-else class="upload-btn" style="height: 120px;" @click="uploadPicture('flagImg')">
            <i class="el-icon-plus" style="font-size: 30px;"></i>
            <span>封面设置</span>
          </div>
        </div>
        <input type="hidden" v-model="formValidate.mainImage" placeholder="请添加封面">
      </el-form-item>
    </el-form>
    <!-- 剪裁组件弹窗 -->
    <el-dialog
        title="裁切封面"
        :visible.sync="cropperModel"
        width="950px"
        center
       >
     <upload-cropper
         :Name="cropperName"
         @uploadImgSuccess = "handleUploadSuccess"
         ref="child">
     </upload-cropper>
    </el-dialog>
    <!--查看大封面-->
    <el-dialog
        title="查看大封面"
        :visible.sync="imgVisible"
        center>
      <img :src="imgName" v-if="imgVisible" style="width: 100%" alt="查看">
    </el-dialog>
  </div>
</template>
 
<script>
import uploadCropper from "@/components/upload-cropper";
export default {
  name: "Tailoring",
  components: {uploadCropper},
  data () {
    return {
      formValidate: {
        mainImage: '',
      },
      ruleValidate: {
        mainImage: [
          {required: true, message: '请上传封面', trigger: 'blur'}
        ],
      },
      //裁切图片参数
      cropperModel:false,
      cropperName:'',
      imgName: '',
      imgVisible: false
    }
  },
  methods: {
      middleAdFinish(){
 
      },
    //封面设置
    uploadPicture(name){
      this.cropperName = name;
      this.cropperModel = true;
    },
    //图片上传成功后
    handleUploadSuccess (data){
      console.log(data)
      switch(data.name){
        case 'flagImg':
          this.formValidate.mainImage = 'http://ydfblog.cn/dfs/'+data.url;
          console.log('最终输出'+data.name)
          break;
      }
      this.cropperModel = false;
    }
  }
}
</script>
<style scoped>
  .upload-list-cover{
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      padding: 0 40px;
      align-items: center;
      background: rgba(0,0,0,.6);
      opacity: 0;
      transition: opacity 1s;
  }
  .cover_icon {
    font-size: 30px;
  }
  .upload-btn{
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    border: 1px solid #cccccc;
    border-radius: 5px;
    overflow: hidden;
    box-shadow: 0 0 1px #cccccc;
  }
  .upload-btn:hover {
    border: 1px solid #69b7ed;
  }
  .upload-btn i{
    margin: 5px;
  }
</style>
实例2

test.vue:

<template>
  <div style="display:flex;">
    <div class="info-item" style="flex:1;">
      <div style="width:120px;height:120px;border-radius:50%;overflow:hidden;margin-left:123px;border:1px solid #ddd">
        <img style="width:120px;height:120px;" :src="headImg" alt="头像">
      </div>
    </div>
    <div class="info-item" style="flex:1;margin-left:-160px;margin-top:30px;">
      <label class="btn btn-orange" for="uploads" style="display:inline-block;width: 70px;padding: 0;text-align: center;line-height: 28px;">选择图片</label>
      <input type="file" id="uploads" :value="imgFile" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event, 1)">
      <input type="button" class="oper" style="height:20px;width:23px;font-size:20px;margin:3px 5px;" value="+" title="放大" @click="changeScale(1)">
      <input type="button" class="oper" style="height:20px;width:23px;font-size:20px;margin:3px 5px;" value="-" title="缩小" @click="changeScale(-1)">
      <input type="button" class="oper" style="height:20px;width:23px;font-size:20px;margin:3px 5px;" value="↺" title="左旋转" @click="rotateLeft">
      <input type="button" class="oper" style="height:20px;width:23px;font-size:20px;margin:3px 5px;" value="↻" title="右旋转" @click="rotateRight">
      <input type="button" class="oper" style="height:20px;width:23px;font-size:20px;margin:3px 5px;" value="↓" title="下载" @click="down('blob')">
      <input type="button" class="btn btn-blue" value="上传头像" @click="finish('blob')">
      <div class="line" style="margin-left: -280px;margin-top: 85px;">
        <div class="cropper-content" style="margin-top:-60px;margin-left:260px;">
          <div class="cropper">
            <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"
              @realTime="realTime"
              @imgLoad="imgLoad"
            ></vueCropper>
          </div>
          <div style="margin-left:20px;">
            <div class="show-preview" :style="{'width': '150px', 'height':'155px',  'overflow': 'hidden', 'margin': '5px'}">
              <div :style="previews.div" class="preview">
                <img :src="previews.url" :style="previews.img">
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  import VueCropper from 'vue-cropper'
  import Api from '@/js/api.js' //接口url配置文件

  export default {
    data() {
      return {
        headImg:'',
        //剪切图片上传
        crap: false,
        previews: {},
        option: {
          img: '',
          outputSize:1, //剪切后的图片质量(0.1-1)
          full: false,//输出原图比例截图 props名full
          outputType: 'png',
          canMove: true, 
          original: false, 
          canMoveBox: true, 
          autoCrop: true, 
          autoCropWidth: 150, 
          autoCropHeight: 150, 
          fixedBox: true 
        }, 
        fileName:'',  //本机文件地址
        downImg: '#',
        imgFile:'',
        uploadImgRelaPath:'', //上传后的图片的地址(不带服务器域名)
      }
    },
    components: { 
      VueCropper 
    }, 
    methods: { 
      //放大/缩小
      changeScale(num) { 
        console.log('changeScale')
        num = num || 1; 
        this.$refs.cropper.changeScale(num); 
      }, 
      //坐旋转
      rotateLeft() { 
        console.log('rotateLeft')
        this.$refs.cropper.rotateLeft(); 
      }, 
      //右旋转
      rotateRight() { 
        console.log('rotateRight')
        this.$refs.cropper.rotateRight(); 
      }, 
      //上传图片(点击上传按钮)
      finish(type) { 
        console.log('finish')
        let _this = this;
        let formData = new FormData();
        // 输出 
        if (type === 'blob') { 
          this.$refs.cropper.getCropBlob((data) => { 
            let img = window.URL.createObjectURL(data) 
            this.model = true; 
            this.modelSrc = img; 
            formData.append("file", data, this.fileName);
            this.$http.post(Api.uploadSysHeadImg.url, formData, {contentType: false, processData: false, headers:{'Content-Type': 'application/x-www-form-urlencoded'}})
            .then((response)=>{
              var res = response.data;
              if(res.success == 1){
                $('#btn1').val('');
                _this.imgFile = '';
                _this.headImg = res.realPathList[0];  //完整路径
                _this.uploadImgRelaPath = res.relaPathList[0];  //非完整路径
                _this.$message({  //element-ui的消息Message消息提示组件
                  type: 'success',
                  message: '上传成功'
                });
              }
            })
          }) 
        } else { 
          this.$refs.cropper.getCropData((data) => { 
            this.model = true; 
            this.modelSrc = data; 
          }) 
        } 
      }, 
      // 实时预览函数 
      realTime(data) { 
        console.log('realTime')
        this.previews = data 
      }, 
      //下载图片
      down(type) { 
        console.log('down')
        var aLink = document.createElement('a') 
        aLink.download = 'author-img' 
        if (type === 'blob') { 
          this.$refs.cropper.getCropBlob((data) => { 
            this.downImg = window.URL.createObjectURL(data)
            aLink.href = window.URL.createObjectURL(data) 
            aLink.click() 
          }) 
        } else { 
          this.$refs.cropper.getCropData((data) => { 
            this.downImg = data;
            aLink.href = data; 
            aLink.click() 
          }) 
        } 
      }, 
      //选择本地图片
      uploadImg(e, num) { 
        console.log('uploadImg');
        var _this = this;
        //上传图片 
        var file = e.target.files[0] 
        _this.fileName = file.name;
        if (!/.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) { 
          alert('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种') 
          return false 
        } 
        var reader = new FileReader(); 
        reader.onload =(e) => { 
          let data; 
          if (typeof e.target.result === 'object') { 
            // 把Array Buffer转化为blob 如果是base64不需要 
            data = window.URL.createObjectURL(new Blob([e.target.result])) 
          } 
          else { 
            data = e.target.result 
          }
          if (num === 1) { 
            _this.option.img = data 
          } else if (num === 2) { 
            _this.example2.img = data 
          } 
        } 
        // 转化为base64 
        // reader.readAsDataURL(file) 
        // 转化为blob 
        reader.readAsArrayBuffer(file);
        
      }, 
      imgLoad (msg) { 
        console.log('imgLoad')
        console.log(msg) 
      }
    }, 
    
  }
</script>

<style lang="less">
  .info {
    width: 720px;
    margin: 0 auto;
    .oper-dv {
      height:20px;
      text-align:right;
      margin-right:100px;
      a {
        font-weight: 500;
        &:last-child {
          margin-left: 30px;
        }
      }
    }
    .info-item {
      margin-top: 15px;
      label {
        display: inline-block;
        width: 100px;
        text-align: right;
      }
      .sel-img-dv {
        position: relative;
        .sel-file {
          position: absolute;
          width: 90px;
          height: 30px;
          opacity: 0;
          cursor: pointer;
          z-index: 2;
        }
        .sel-btn {
          position: absolute;
          cursor: pointer;
          z-index: 1;
        }
      }
    }
  }

  .cropper-content{
    display: flex;
    display: -webkit-flex;
    justify-content: flex-end;
    -webkit-justify-content: flex-end;
    .cropper{
      width: 260px;
      height: 260px;
    }
    .show-preview{
      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: #cccccc;
        margin-left: 40px;
      }
    }
  }
  .cropper-content .show-preview .preview {margin-left: 0;}
 
</style>

其中,js/api.js文件是配置的接口地址

1、打开页面效果

在这里插入图片描述

2、点击选择图片按钮,选择完本地图片后的效果

在这里插入图片描述

选择完图片后,就可以对图片进行放大,缩小以及旋转等,并且可以移动选中框,选择上传图片的任意部分

3、点击上传头像按钮,即可调用上传头像的接口,把头像上传到文件服务器;

4、此时,图片便已上传成功了,查看图片服务器指定的目录,即可查看到图片已经在服务器上了

实例3-完整版

1、安装

npm install vue-cropper --save

2、页面引入

import { VueCropper } from 'vue-cropper'

3、申明组件

components: {
    VueCropper,
 },

4、完整代码

<!-- 裁剪图片 -->
<template>
  <div class="wrapper">
    <div class="model" v-show="model" @click="model = false">
      <div class="model-show">
        <img :src="modelSrc" alt="">
      </div>
    </div>
    <div class="content">

      <div class="show-info">
        <h2>自动生成截图框 固定比例 w : h => 4 : 3</h2>
        <div class="test">
          <vueCropper ref="cropper2"
                      :img="example2.img"
                      :outputSize="example2.size"
                      :outputType="example2.outputType"
                      :info="example2.info"
                      :canScale="example2.canScale"
                      :autoCrop="example2.autoCrop"
                      :autoCropWidth="example2.autoCropWidth"
                      :autoCropHeight="example2.autoCropHeight"
                      :fixed="example2.fixed"
                      :fixedNumber="example2.fixedNumber"
                      :enlarge="4"></vueCropper>
        </div>
        <label class="btn" for="upload2">上传</label>
        <input type="file" id="upload2" style="position:absolute; clip:rect(0 0 0 0);"
               accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event,2)">
        <button @click="finish2()" class="btn">裁剪</button>
      </div>
    </div>

  </div>
</template>

<script>
  import { VueCropper } from 'vue-cropper'
  // import * as OSS from 'ali-oss';
  export default {
    components: {
      VueCropper,
    },
    data() {
      return {
        model: false,
        modelSrc: '',
        crap: false,
        previews: {},
        form: {
          head: ''
        },
        example2: {
          //img的路径自行修改
          img: '$oss.url + \'/\' + form.head ',
          info: true,
          size: 1,
          outputType: 'jpeg',
          canScale: true,
          autoCrop: true,
          // 只有自动截图开启 宽度高度才生效
          autoCropWidth: 300,
          autoCropHeight: 250,
          fixed: true,
          // 真实的输出宽高
          infoTrue: true,
          fixedNumber: [4, 3]
        },
        downImg: '#'
      }
    },
    methods: {
      //点击裁剪,这一步是可以拿到处理后的地址
      finish2() {
        this.$refs.cropper2.getCropData((data) => {
          this.modelSrc = data
          this.model = false;
          //裁剪后的图片显示
          this.example2.img = this.modelSrc;
          // this.toBlob(data)
          // console.log(data)
          // console.log(this.toBlob(data))

          //将图片上传服务器中

        })

      },

      uploadImg(e, num) {
        //上传图片
        this.example2.img = ''
        var file = e.target.files[0]
        if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
          alert('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种')
          return false
        }
        var reader = new FileReader()
        reader.onload = (e) => {
          let data
          data = e.target.result
          if (typeof e.target.result === 'object') {
            // 把Array Buffer转化为blob 如果是base64不需要
            data = window.URL.createObjectURL(new Blob([e.target.result]))
          } else {
            data = e.target.result
          }
          if (num === 1) {
            this.option.img = data
          } else if (num === 2) {
            this.example2.img = data
          }
        }
        // 转化为base64
        // reader.readAsDataURL(file)
        // 转化为blobcs
        reader.readAsArrayBuffer(file)
      },
      // base64转blob
      toBlob(ndata) {
        //ndata为base64格式地址
        console.log(ndata)
        let arr = ndata.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n);
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n);
        }
        return new Blob([u8arr], {
          type: mime
        })
      }
    },

  }
</script>

<style>
  * {
    margin: 0;
    padding: 0;
  }

  .content {
    margin: auto;
    max-width: 585px;
    margin-bottom: 100px;
  }

  .test-button {
    display: flex;
    flex-wrap: wrap;
  }

  .btn {
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    background: #fff;
    border: 1px solid #c0ccda;
    color: #1f2d3d;
    text-align: center;
    box-sizing: border-box;
    outline: none;
    margin: 20px 10px 0px 0px;
    padding: 9px 15px;
    font-size: 14px;
    border-radius: 4px;
    color: #fff;
    background-color: #50bfff;
    border-color: #50bfff;
    transition: all .2s ease;
    text-decoration: none;
    user-select: none;
  }

  .des {
    line-height: 30px;
  }

  code.language-html {
    padding: 10px 20px;
    margin: 10px 0px;
    display: block;
    background-color: #333;
    color: #fff;
    overflow-x: auto;
    font-family: Consolas, Monaco, Droid, Sans, Mono, Source, Code, Pro, Menlo, Lucida, Sans, Type, Writer, Ubuntu, Mono;
    border-radius: 5px;
    white-space: pre;
  }

  .show-info {
    margin-bottom: 50px;
  }

  .show-info h2 {
    line-height: 50px;
  }

  /*.title, .title:hover, .title-focus, .title:visited {
        color: black;
    }*/

  .title {
    display: block;
    text-decoration: none;
    text-align: center;
    line-height: 1.5;
    margin: 20px 0px;
    background-image: -webkit-linear-gradient(left, #3498db, #f47920 10%, #d71345 20%, #f7acbc 30%, #ffd400 40%, #3498db 50%, #f47920 60%, #d71345 70%, #f7acbc 80%, #ffd400 90%, #3498db);
    color: transparent;
    -webkit-background-clip: text;
    background-size: 200% 100%;
    animation: slide 5s infinite linear;
    font-size: 40px;
  }

  .test {
    height: 285px;
  }

  .model {
    position: fixed;
    z-index: 10;
    width: 100vw;
    height: 100vh;
    overflow: auto;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.8);
  }

  .model-show {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100vw;
    height: 100vh;
  }

  .model img {
    display: block;
    margin: auto;
    max-width: 80%;
    user-select: none;
    background-position: 0px 0px, 10px 10px;
    background-size: 20px 20px;
    background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee 100%), linear-gradient(45deg, #eee 25%, white 25%, white 75%, #eee 75%, #eee 100%);
  }

  .c-item {
    display: block;
    padding: 10px 0;
    user-select: none;
  }

  @keyframes slide {
    0% {
      background-position: 0 0;
    }

    100% {
      background-position: -100% 0;
    }
  }

  @media screen and (max-width: 1000px) {
    .content {
      max-width: 90%;
      margin: auto;
    }

    .test {
      height: 400px;
    }
  }
</style>
实例4

1、安装

npm install vue-cropper

2、使用

1.main.js文件引入

import VueCropper from 'vue-cropper' 
Vue.use(VueCropper)

2.封装

<template>
  <div>
    <el-dialog
      title="图片剪裁"
      :visible.sync="dialogVisiblex"
      :close-on-press-escape="false"
      :close-on-click-modal="false"
      append-to-body
      width="1000px"
    >
      <div class="cropper-content">
        <div class="cropper" style="text-align:center">
          <vueCropper
            ref="cropper"
            :img="option.img"
            :outputSize="option.outputSize"
            :outputType="option.outputType"
            :info="option.info"
            :canScale="option.canScale"
            :autoCrop="option.autoCrop"
            :autoCropWidth="option.autoCropWidth"
            :autoCropHeight="option.autoCropHeight"
            :fixedBox="option.fixedBox"
            :fixed="option.fixed"
            :fixedNumber="option.fixedNumber"
            :canMove="option.canMove"
            :canMoveBox="option.canMoveBox"
            :original="option.original"
            :centerBox="option.centerBox"
            :infoTrue="option.infoTrue"
            :full="option.full"
            :enlarge="option.enlarge"
            :mode="option.mode"
          >
          </vueCropper>
        </div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisiblex = false">取消</el-button>
        <el-button type="primary" @click="finish" :loading="loading"
          >确认</el-button
        >
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  components: {},
  props: {},
  data() {
    return {
      dialogVisiblex: false,
      loading: false,
      option: {
        img: '', // 裁剪图片的地址 url 地址, base64, blob
        outputSize: 1, // 裁剪生成图片的质量
        outputType: 'jpeg', // 裁剪生成图片的格式 jpeg, png, webp
        info: true, // 裁剪框的大小信息
        canScale: false, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        autoCropWidth: 345, // 默认生成截图框宽度
        autoCropHeight: 245, // 默认生成截图框高度
        fixedBox: false, // 固定截图框大小 不允许改变
        fixed: true, // 是否开启截图框宽高固定比例
        fixedNumber: [1, 1], // 截图框的宽高比例 [ 宽度 , 高度 ]
        canMove: true, // 上传图片是否可以移动
        canMoveBox: true, // 截图框能否拖动
        original: false, // 上传图片按照原始比例渲染
        centerBox: true, // 截图框是否被限制在图片里面
        infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
        full: true, // 是否输出原图比例的截图
        enlarge: '1', // 图片根据截图框输出比例倍数
        mode: 'contain' // 图片默认渲染方式 contain , cover, 100px, 100% auto
      },
      unimgurl: '',
      success: () => {} // 回调方法
    }
  },
  computed: {},
  watch: {},
  created() {

  },
  mounted() {},
  activated() {},
  methods: {
    showModal(obj) {
      if (obj.img) {
        this.option.img = obj.img
      }
      //裁剪生成图片的质量
      if (obj.outputSize) {
        this.option.outputSize = obj.outputSize
      } else {
        this.option.outputSize = 1
      }
      //裁剪生成图片的格式
      if (obj.outputType) {
        this.option.outputType = obj.outputType
      } else {
        this.option.outputType = 'jpeg'
      }
      //裁剪框的大小信息
      if (obj.info) {
        this.option.info = obj.info
      } else {
        this.option.info = true
      }
      //图片是否允许滚轮缩放
      if (obj.canScale) {
        this.option.canScale = obj.canScale
      } else {
        this.option.canScale = false
      }
      //是否默认生成截图框
      if (obj.autoCrop) {
        this.option.autoCrop = obj.autoCrop
      } else {
        this.option.autoCrop = true
      }
      //默认生成截图框宽度
      if (obj.autoCropWidth) {
        this.option.autoCropWidth = obj.autoCropWidth
      } else {
        this.option.autoCropWidth = 375
      }
      //默认生成截图框高度
      if (obj.autoCropHeight) {
        this.option.autoCropHeight = obj.autoCropHeight
      } else {
        this.option.autoCropHeight = 245
      }
      //固定截图框大小 不允许改变
      if (obj.fixedBox) {
        this.option.fixedBox = obj.fixedBox
      } else {
        this.option.fixedBox = false
      }
      //是否开启截图框宽高固定比例
      if (obj.fixed) {
        this.option.fixed = obj.fixed
      } else {
        this.option.fixed = true
      }
      //截图框的宽高比例
      if (obj.fixedNumber) {
        this.option.fixedNumber = obj.fixedNumber
      } else {
        this.option.fixedNumber = [this.option.autoCropWidth, this.option.autoCropHeight]
      }
      //上传图片是否可以移动
      if (obj.canMove) {
        this.option.canMove = obj.canMove
      } else {
        this.option.canMove = true
      }
      //截图框能否拖动
      if (obj.canMoveBox) {
        this.option.canMoveBox = obj.canMoveBox
      } else {
        this.option.canMoveBox = true
      }
      //上传图片按照原始比例渲染
      if (obj.original) {
        this.option.original = obj.original
      } else {
        this.option.original = false
      }
      //截图框是否被限制在图片里面
      if (obj.centerBox) {
        this.option.centerBox = obj.centerBox
      } else {
        this.option.centerBox = true
      }
      //true 为展示真实输出图片宽高 false 展示看到的截图框宽高
      if (obj.infoTrue) {
        this.option.infoTrue = obj.infoTrue
      } else {
        this.option.infoTrue = true
      }
      //是否输出原图比例的截图
      if (obj.full) {
        this.option.full = obj.full
      } else {
        this.option.full = true
      }
      //图片根据截图框输出比例倍数
      if (obj.enlarge) {
        this.option.enlarge = obj.enlarge
      } else {
        this.option.enlarge = '1'
      }
      //图片默认渲染方式
      if (obj.mode) {
        this.option.mode = obj.mode
      } else {
        this.option.mode = 'contain'
      }
      if (obj.success) {
        this.success = obj.success
      } else {
        this.success = () => {}
      }
      this.dialogVisiblex = true
    },
    finish() {
      // 获取截图的数据
      let that = this
      this.$refs.cropper.getCropBlob(data => {
        that.unimgurl = data
        that.confirm()
      })
    },
    confirm() {
      this.success({
        img: this.unimgurl
      })
      this.dialogVisiblex = false
    },
    cancel() {
      this.dialogVisiblex = false
    }
  }
}
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.real_info_class {
  .el-checkbox__input .el-checkbox__inner {
    border-radius: 0;
  }
}
.file-image {
  width: 320px;
  height: 320px;
  font-size: 14px;
  border: 1px solid #cccccc;
  margin: 15px 0;
}

/* 截图 */
/* .cropper-content {} */
.cropper {
  width: 960px;
  height: 606px;
}
</style>

3.组件调用

 <x-cropper ref="iscropper"></x-cropper>
 this.$refs.iscropper.showModal({
        img: img, // 裁剪图片的地址
        outputSize: 0.8, // 裁剪生成图片的质量
        outputType: 'jpeg', // 裁剪生成图片的格式
        info: true, // 裁剪框的大小信息
        canScale: false, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        autoCropWidth: 375, // 默认生成截图框宽度
        autoCropHeight: 245, // 默认生成截图框高度
        fixedNumber: [1, 1], // 截图框的宽高比例
        fixedBox: false, // 固定截图框大小 不允许改变
        fixed: false, // 是否开启截图框宽高固定比例
        canMove: true, // 上传图片是否可以移动
        canMoveBox: true, // 截图框能否拖动
        original: false, // 上传图片按照原始比例渲染
        centerBox: true, // 截图框是否被限制在图片里面
        infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
        full: true, // 是否输出原图比例的截图
        enlarge: '1', // 图片根据截图框输出比例倍数
        mode: 'contain', // 图片默认渲染方式
        success: res => {
          this.unimgurl = res.img
          this.imageUrl = URL.createObjectURL(res.img)
        }
      })

省略

 this.$refs.iscropper.showModal({
    img: img, // 裁剪图片的地址
    autoCropWidth: 375, // 默认生成截图框宽度
    autoCropHeight: 245, // 默认生成截图框高度
    success: res => {
      this.unimgurl = res.img
      this.imageUrl = URL.createObjectURL(res.img)
    }
  })

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/66866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习分享:如何进行全局变量的学习

​对于很多朋友&#xff0c;尤其是刚接触全局变量的朋友而言&#xff0c;全局变量的学习对他们来说不是一件容易的事情。关于这方面的学习&#xff0c;很多朋友不太理解它的用法及分析方法&#xff0c;所以会比较乱&#xff0c;难以掌握。 什么是axure全局变量&#xff1f;全局…

【STM32】详解PWM的概念和原理

PWM的概念和原理一、PWM是什么&#xff1f;二、如何实现&#xff1f;三、STM32中的PWM四、使用库函数配置PWM将LED0设置为呼吸灯一、PWM是什么&#xff1f; PWM&#xff08;Pulse width modulation&#xff09;脉冲宽度调制。PWM是通过编程控制输出方波的频率和占空比&#xf…

oracle自启动的p***并行进程过多导致的process进程超限问题

某项目现场反馈无任何业务连接&#xff0c;查询v$process仍有500多个进程&#xff1b; 查询会话连接&#xff0c;也只有十几个会话&#xff1b; select b.MACHINE, b.PROGRAM,b.USERNAME, count(*) from v$process a, v$session b where a.ADDR b.PADDR and b.USERNAME is…

RCNN学习笔记-ResNeXt

论文地址&#xff1a;https://arxiv.org/pdf/1611.05431.pdf Abstract 我们提出了一种简单、高度模块化的图像分类网络体系结构。我们的网络是通过重复一个构建块来构建的&#xff0c;该构建块聚合了一组具有相同拓扑的变换。我们的简单设计产生了一个只有几个超参数可设置的…

JavaScript -- 数组常用方法及示例代码总结

文章目录数组的方法1 Array.isArray()2 at()3 concat()4 indexOf()5 lastIndexOf()6 join()7 slice()8 push()9 pop()10 unshift()11 shift()12 splice()13 reverse()14 sort()15 forEach()16 filter()17 map()18 reduce()数组的方法 Array参考文档&#xff1a;https://develo…

AIoT通用组件服务攻略之设备“收纳”好帮手——分组管理

天翼物联网平台&#xff08;AIoT&#xff09;通用组件服务提供设备分组管理功能&#xff0c;既可将单个产品下的部分设备划成一个分组&#xff0c;也可将多个产品下的设备划成一个统一分组&#xff0c;主要用于对设备进行归类管理&#xff0c;便于对设备进行批量操作。 对设备…

Java中高级核心知识全面解析——类加载过程

一个非数组类的加载阶段&#xff08;加载阶段获取类的二进制字节流的动作&#xff09;是可控性最强的阶段&#xff0c;这一步我们可以去完成还可以自定义类加载器去控制字节流的获取方式&#xff08;重写一个类加载器的 loadClass() 方法&#xff09;。数组类型不通过类加载器创…

适用于嵌入式单片机的差分升级通用库+详细教程

1. 什么是差分/增量升级&#xff1f; 借用网上的介绍&#xff1a;适合嵌入式的差分升级又叫增量升级&#xff0c;顾名思义就是通过差分算法将源版本与目标版本之间差异的部分提取出来制作成差分包&#xff0c;然后在设备通过还原算法将差异部分在源版本上进行还原从而升级成目…

Jekyll如何自定义摘要

最近搭建博客网站的时候遇到一个问题&#xff1a;博客的摘要包含了内容的格式&#xff0c;比如下面这张图。 标题的样式显示在摘要中&#xff0c;这可太奇怪了。我在查找文档之后没有想到合适的解决方案&#xff0c;于是乎就去 Jekyll 的项目下面提了个 Issue 问了一下。 在…

js原生实现步骤条

实现思路: 1.定義一個流程數組和一个步骤状态 2.遍历这个流程数组&#xff0c;如果步骤状态大于流程&#xff0c;checked&#xff1d;true&#xff0c; 3.页面输出遍历的流程数组&#xff0c;checked的div点亮 最终效果 <!DOCTYPE html> <html> <title>js原…

音视频开发:直播推流技术指南

一、推流架构 推流SDK客户端的模块主要有三个&#xff0c;推流采集端、队列控制模块、推流端。其中每个模块的主要流程如下&#xff0c;本文的主要目的就是拆分推流流程。 1.1 采集端 视频采集&#xff1a;通过Camera采集视频。 音频采集&#xff1a;通过麦克风采集音频。 …

HTML做一个节日页面【六一儿童节】纯HTML代码

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

「动态规划学习心得」正则表达式匹配

正则表达式匹配 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。 ‘.’ 匹配任意单个字符‘*’ 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s的&#xff0c;而不是部分字符串。 输入&…

客户管理系统中的常用术语都有哪些 (下)

CRM客户管理系统概念问世的二十多年来&#xff0c;曾帮助过无数企业打造优质的客户关系&#xff0c;带来显著的业绩增长。为了让您有更好的理解&#xff0c;小编把CRM常用术语进行了汇总&#xff0c;希望能够帮助到正在了解CRM的您。 销售方法及营销理念 LTC (Leads To Cash)…

超细节的javaWeb知识点总结

文章目录Servlet系统架构C/S架构B/S架构C/S和B/S结构的系统&#xff0c;哪个好&#xff0c;哪个不好&#xff1f;JavaEE是什么&#xff1f;B/S结构的系统通信原理&#xff08;没有涉及到Java小程序&#xff09;WEB系统的访问过程关于域名&#xff1a;IP地址是啥&#xff1f;端口…

搜索与图论-树与图的广度优先遍历

文章目录一、树与图的广度优先遍历1. 构建2. 遍历3. 具体实现详见例题——图中点的层次二、树与图的广度优先遍历例题——图中点的层次具体实现&#xff08;一&#xff09;1. 样例演示2. 实现思路3. 代码注解4. 实现代码具体实现&#xff08;二&#xff09;1. 代码注解2. 实现代…

JupyterLab | 这几款插件推荐给天天使用JupyterLab的你!~

1写在前面 最近用了用JupyterLab&#xff0c;总体来说体验还是不错的&#xff0c;代码写完就是一篇完整的Paper了&#xff0c;非常给力。&#x1f973; 不过单纯使用JupyterLab可能还是有一些不尽人意的地方&#xff0c;这些问题基本都可以通过添加插件来弥补&#xff0c;今天就…

内存可见性问题

目录 1.什么是内存可见性问题 2.内存可见性问题是怎么发生的 3.解决方法&#xff1a;volatile 4.volatile使用的注意事项 5.内存可见性问题的延伸 缓存&#xff08;cache&#xff09; 1.什么是内存可见性问题 首先来看一段代码 class Counter{public int flag 0; } pu…

docker部署redis集群 删除节点(缩容)

上篇博文完成了redis集群的搭建&#xff1a;点这里 以及redis集群的添加节点 即扩容&#xff1a;点这里 本篇博文写一下怎样在redis集群中删除节点&#xff08;还是在之前博文的基础上&#xff09;&#xff0c;博文中的111.111.111.111均换成实际IP使用 删除从节点 我这里想…

大数据学习:进程管理

文章目录一、进程ID&#xff08;PID&#xff09;二、查看进程1、进程查看命令-ps&#xff08;1&#xff09;命令作用&#xff08;2&#xff09;参数说明&#xff08;3&#xff09;操作案例2、Linux进程状态3、观察进程变化命令 -top&#xff08;1&#xff09;参数选项&#xff…