• vue 图片裁剪并回传显示


    vue 图片裁剪并回传显示

    数据页面::ResourceUrl="resourceUrl",注意,该代码是向裁剪页回传图片数据

    <template>
      <div>
        <el-dialog :visible.sync="visible" :title="!dataForm.id ? $t('add') : $t('update')" :close-on-click-modal="false" :close-on-press-escape="false">
            <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmitHandle()" label-width="120px">
            <el-form-item prop="coverUrl" :label="$t('course.coverUrl')">
                <div class="list-img-box"> 
                  <img :src="courseUrl" style='width:120px;height:120px;border:none;' alt="自定义图片" @error="imgError()"><br/>
                  <el-button type="text" @click="uploadPicture('flagImg')">修改图片</el-button>
                </div>
                <input type="hidden" v-model="dataForm.coverUrl" placeholder="请添加图片">
            </el-form-item>
            </el-form>
            <template slot="footer">
            <el-button @click="visible = false">{{ $t('cancel') }}</el-button>
            <el-button type="primary" @click="dataFormSubmitHandle()">{{ $t('confirm') }}</el-button>
            </template>
        </el-dialog>
        <!-- 弹窗, 上传文件 -->
      <upload v-if="uploadVisible" ref="upload" @uploadback="uploadUrl"></upload>
      <!-- 剪裁组件弹窗 -->
      <el-dialog title="裁切封面" :visible.sync="cropperModel" v-if="cropperModel" width="1130px" center append-to-body :before-close="dialogClose">
        <cropper-image :Name="cropperName" :ResourceUrl="resourceUrl" @uploadImgSuccess = "handleUploadSuccess" ref="child" :key="componentKey">
        </cropper-image>
      </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 debounce from 'lodash/debounce'
    import CropperImage from './cropperImage'
    export default {
      data () {
        return {
          visible: false,
          dataForm: {
            id: '',
            coverUrl: ''
          },
          courseUrl: '',
          // 裁切图片参数
          cropperModel: false,
          cropperName: '',
          resourceUrl: '',
          imgName: '',
          imgVisible: false,
          // 该参数作用是点击上传图片确定按钮后,刷新页面数据
          componentKey: 0
        }
      },
      components: {
          CropperImage
      },
      methods: {
        init () {
          this.visible = true
          this.$nextTick(() => {
            this.courseUrl = ''
            this.$refs['dataForm'].resetFields()
            if (this.dataForm.id) {
              this.getInfo()
            }
          })
        },
        // 封面设置
        uploadPicture (name) {
          this.cropperName = name
          this.cropperModel = true
        },
        // 点击叉号,关闭弹窗
        dialogClose () {
          this.cropperModel = false
          // 点击叉号,清除之前上传的图片
          this.resourceUrl = ''
          this.$emit('refreshDataList')
        },
        // 图片上传成功后
        handleUploadSuccess (data) {
          this.dataForm.coverUrl = data.url
          this.courseUrl = `${window.SITE_CONFIG['apiURL']}` + data.url 
          this.cropperModel = false
          // 清除之前上传的图片
          this.resourceUrl = ''
          this.$emit('refreshDataList')
        },
        // 默认头像
        imgError() {
          this.courseUrl = require('@/assets/img/course.png');
        },
        // 获取信息
        getInfo () {
          this.$http.get(`/cd/course/info/${this.dataForm.id}`).then(({ data: res }) => {
            if (res.code !== 0) {
              return this.$message.error(res.msg)
            }
            this.dataForm = {
              ...this.dataForm,
              ...res.data
            }
            if (res.data.coverUrl != null) {
                let prefixUrl = `${window.SITE_CONFIG['apiURL']}`
                this.courseUrl = prefixUrl + res.data.coverUrl
                // 回显的图片路径
                this.resourceUrl = res.data.coverUrl
            }
          }).catch(() => {})
        },
        // 上传文件
        uploadHandle () {
          this.uploadVisible = true
          let type = 0
          this.$nextTick(() => {
            this.$refs.upload.init(type)
          })
        },
        // 上传文件成功后,子组件回传到父组件资源id
        uploadUrl (val) {
            this.dataForm.coverUrl = val.resourceUrl
            let prefixUrl = `${window.SITE_CONFIG['apiURL']}`
            this.courseUrl = prefixUrl + val.resourceUrl
        },
        // 表单提交
        dataFormSubmitHandle: debounce(function () {
          this.$refs['dataForm'].validate((valid) => {
            if (!valid) {
              return false
            }
            this.$http[!this.dataForm.id ? 'post' : 'put']('/cd/course', this.dataForm).then(({ data: res }) => {
              if (res.code !== 0) {
                return this.$message.error(res.msg)
              }
              this.$message({
                message: this.$t('prompt.success'),
                type: 'success',
                duration: 500,
                onClose: () => {
                  this.visible = false
                  this.componentKey += 1;  
                  this.$emit('refreshDataList')
                }
              })
            }).catch(() => {})
          })
        }, 1000, { 'leading': true, 'trailing': false })
      }
    }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151

    裁剪页面:

    <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'
    import Cookies from 'js-cookie'
    export default {
      name: 'CropperImage',
      components: {
        VueCropper
      },
      props: ['Name','ResourceUrl'],
      data () {
        return {
          name: this.Name,
          resourceUrl: this.ResourceUrl,
          previews: {},
          option: {
            img: '',             // 裁剪图片的地址
            outputSize: 1,       // 裁剪生成图片的质量(可选0.1 - 1)
            outputType: 'jpeg',  // 裁剪生成图片的格式(jpeg || png || webp)
            info: true,          // 图片大小信息
            canScale: true,      // 图片是否允许滚轮缩放
            autoCrop: true,      // 是否默认生成截图框
            autoCropWidth: 500,  // 默认生成截图框宽度
            autoCropHeight: 320, // 默认生成截图框高度
            fixed: true,         // 是否开启截图框宽高固定比例
            fixedNumber: [25, 16],  // 截图框的宽高比例
            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: '500px 320px', // 图片默认渲染方式
            filename: '',
            //centerBox: false, // 截图框是否被限制在图片里面
            fixed: false, // 是否开启截图框宽高固定比例
          }
        }
      },
      mounted() {
        let prefixUrl = `${window.SITE_CONFIG['apiURL']}`
        let url =  prefixUrl + this.resourceUrl;
        // 回传的数据是base64,所以在这里将接收到的图片路径转base64格式
        this.toBase64(url)
      },
      methods: {
        toBase64(imgUrl) {
        // 一定要设置为let,不然图片不显示
        let image = new Image();
        // 解决跨域问题
        image.setAttribute('crossOrigin', 'anonymous');
        let imageUrl = imgUrl;
        image.src = imageUrl
        // image.onload为异步加载
        image.onload = () => {
            let canvas = document.createElement('canvas');
            canvas.width = image.width;
            canvas.height = image.height;
            let context = canvas.getContext('2d');
            context.drawImage(image, 0, 0, image.width, image.height);
            let quality = 0.8;
            // 这里的dataurl就是base64类型  
            // 使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png,因为压缩成png后base64的字符串可能比不转换前的长!
            let dataurl = canvas.toDataURL('image/jpeg', quality);
            this.option.img = dataurl
            }
        },
        // 初始化函数
        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]
          this.filename = file.name
          if (!/\.(jpg|jpeg|png|gif|JPG|PNG|GIF)$/.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) {
          if (type === 'blob') {
            // 获取截图的blob数据
            this.$refs.cropper.getCropBlob((data) => {
              let formData = new FormData()
              formData.append('file', data, this.filename)
              this.$http({
                url: `${window.SITE_CONFIG['apiURL']}/cd/resource/upload?token=${Cookies.get('token')}`,
                method: 'post',
                data: formData
              }).then(({data}) => {
                if (data.code === 0) {
                  this.$message({
                    message: '上传成功',
                    type: 'success'
                  })
                  console.log("-------",data)
                  let imgInfo = {
                    name: this.Name,
                    url: data.data.resourceUrl
                  }
                  this.$emit('uploadImgSuccess', imgInfo)
                } else {
                  this.$message({
                    message: '文件服务异常,请联系管理员!',
                    type: 'error'
                  })
                }
              })
            })
          }
        }
      }
    }
    </script>
    
    <style scoped lang="scss">
    
    .cropper-content{
      display: flex;
      display: -webkit-flex;
      justify-content: flex-end;
      .cropper-box{
        flex: 1;
        width: 100%;
        .cropper{
          width: auto;
          height: 400px;
        }
      }
    
      .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;
      .scope-btn{
        display: flex;
        display: -webkit-flex;
        justify-content: space-between;
        padding-right: 10px;
      }
      .upload-btn{
        flex: 1;
        -webkit-flex: 1;
        display: flex;
        display: -webkit-flex;
        justify-content: center;
      }
      .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>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
  • 相关阅读:
    Maven工程继承关系,多个模块要使用同一个框架,它们应该是同一个版本,项目中使用的框架版本需要统一管理。
    关于操作系统安全补丁信息的查询
    oracle 数据链接过多,导致后续链接链接不上
    常用类15:Math类
    请求转发与请求重定向的区别
    设计模式 行为型模式 - 观察者模式(六)
    JavaSE-day01笔记
    剑指offer 28. 顺时针打印矩阵
    LearnOpenGL1.3:着色器
    VBA信息获取与处理第二个专题第五节:实际场景中随机数的利用
  • 原文地址:https://blog.csdn.net/weixin_44021888/article/details/128137665