vue 上传裁剪后的图片至七牛云

项目需求:上传图片,支持裁剪大小,并上传至七牛云存储

(效果图预览) 

一、使用步骤

1、引入库

vue-cropper github地址

# npm 安装
npm install vue-cropper

# vue2 局部引入
import { VueCropper }  from 'vue-cropper' 
components: {
  VueCropper
}

2、使用

示例中只给出了部分参数配置,可以参考官方文档查看更多参数:

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

示例中配置的是获取截图的base64数据,所以这里主要介绍将base64格式的图片上传到七牛云的方法。

官方文档——上传base64编码图片到七牛云 (通过javascript方式上传,xhr原生请求)

使用axios上传base64图片到七牛云

//上传图片
uploadImg() {
     let _this = this;
     let pic;
     this.$refs.cropper.getCropData( data => {    // 获取截图的 base64 数据
         pic = data.substring(23);   // 是23!!!!! 去掉头部的 “data:image/png;base64,”(包括base64后面的逗号)
         var url = "http://upload-z2.qiniup.com/putb64/" + this.fileSize(pic);  // upload.qiniup.com 上传域名适用于华东空间。华北空间使用 upload-z1.qiniup.com,华南空间使用 upload-z2.qiniup.com,北美空间使用 upload-na0.qiniup.com。
         
        // axios上传,this.qiniuToken由后端提供
         axios.post(url,pic,{
               headers: {
                   'Content-Type': 'application/octet-stream',
                   'Authorization': "UpToken " + this.qiniuToken    
               },
               signature: 'yes'
          }).then(res => {
               let imgInfo = {
                   name: _this.Name,
                   url: pic,    // 截图的base64路径
                   data: res.data // 上传的截图在七牛云中保存的hash和key值
               };
          }).catch(err => { })
     });
},

// 通过base64编码字符流计算文件流大小
fileSize(str){
   var fileSize;
   if (str.indexOf('=') > 0) {
       var indexOf = str.indexOf('=');
       str = str.substring(0, indexOf); //把末尾的'='号去掉
   }
   fileSize = parseInt(str.length - (str.length / 8) * 2);
   return fileSize;
},

axios请求中的url地址前缀需要根据所在地区变更,参考注释或者上面给出的官方文档都可以。

3、完整代码 

<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>
            <p v-show="resolutionRatio.length > 0" style="font-size: 14px;">图片原始分辨率{
   
   { resolutionRatio }}</p>
            <p v-show="errorMessage.length > 0" style="font-size: 14px;color: #ff4545;">{
   
   { errorMessage }}</p> 
            <!--底部操作工具按钮-->
            <div class="footer-btn">
                <div class="scope-btn">
                    <el-upload 
                        class="avatar-uploader" 
                        action="upload"
                        :show-file-list="false"
                        :before-upload="(file) => beforeAvatarUpload(file)">
                        <el-button size="mini" type="success" style="height:32px;margin-right:10px;">选择封面</el-button>
                    </el-upload>
                    <el-button size="mini" type="danger" plain icon="el-icon-zoom-in" @click="changeScale(1)" :disabled="btnDisabled">放大</el-button>
                    <el-button size="mini" type="danger" plain icon="el-icon-zoom-out" @click="changeScale(-1)" :disabled="btnDisabled">缩小</el-button>
                    <el-button size="mini" type="danger" plain @click="rotateLeft" :disabled="btnDisabled"><Icon type="ios-undo-outline" style="font-size:16px;margin: -2px 5px 0 0;"/>左旋转</el-button>
                    <el-button size="mini" type="danger" plain @click="rotateRight" :disabled="btnDisabled"><Icon type="ios-share-alt-outline" style="font-size:16px;margin: -2px 5px 0 0;"/>右旋转</el-button>
                </div>
                <div class="upload-btn">
                    <el-button size="mini" type="success" @click="uploadImg" :disabled="btnDisabled">上传封面 <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 { getUploadToken } from '@/api/user';
import axios from 'axios';

export default {
    name: "CropperImage",
    components: {
        VueCropper
    },
    props: ['Name'],
    mounted(){
        this.getQiniuToken();
    },
    data() {
        return {
            name: this.Name,
            qiniuToken:'',
            fileName: '',

            previews: {},
            option: {
                img: '',             //裁剪图片的地址(url 地址, base64, blob)
                outputSize: 1,       //裁剪生成图片的质量(可选0.1 - 1)
                outputType: 'jpeg',  //裁剪生成图片的格式(jpeg || png || webp)
                info: true,          //图片大小信息
                canScale: true,      //图片是否允许滚轮缩放
                autoCrop: true,      //是否默认生成截图框
                autoCropWidth: 200,  //默认生成截图框宽度(800改200)
                autoCropHeight: 150, //默认生成截图框高度(600改150)
                fixed: true,         //是否开启截图框宽高固定比例
                fixedNumber: [4, 3], //截图框的宽高比例
                full: false,         //false按原比例裁切图片,不失真
                fixedBox: false,      //固定截图框大小,不允许改变
                canMove: true,      //上传图片是否可以移动(false改true)
                canMoveBox: true,    //截图框能否拖动
                original: false,     //上传图片按照原始比例渲染
                centerBox: true,    //截图框是否被限制在图片里面
                height: true,        //是否按照设备的dpr 输出等比例图片
                infoTrue: true,     //true为展示真实输出图片宽高,false展示看到的截图框宽高(false改true)
                maxImgSize: 3000,    //限制图片最大宽度和高度
                enlarge: 4,          //图片根据截图框输出比例倍数(1改4)
                // mode: '800px 600px'  //图片默认渲染方式
            },
            resolutionRatio: '',  // 图片分辨率
            errorMessage: '',  // 图片上传过程的错误信息
        };
    },
    methods: {
        // 调用接口获取七牛token
        getQiniuToken() {
            // this.qiniuToken = ...
        },

        // 图片加载的回调, 返回结果 success, error
        imgLoad(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
        },

        // 通过base64编码字符流计算文件流大小
        fileSize(str){
            var fileSize;
            if (str.indexOf('=') > 0) {
                  var indexOf = str.indexOf('=');
                  str = str.substring(0, indexOf); //把末尾的'='号去掉
            }
            fileSize = parseInt(str.length - (str.length / 8) * 2);
            return fileSize;
        },

        // 上传图片之前的钩子
        async beforeAvatarUpload(file){
            let formatArr = ['png','jpg','jpeg'];
            const isPic = ( formatArr.indexOf(file.name.split('.')[1].toLowerCase()) != -1 );
            if ( isPic ) { 
                const isLt2M = file.size / 1024 / 1024 <= 10;
                if ( isLt2M ) {
                    this.resolutionRatio = `${imgPx.width}*${imgPx.height}`;
                    // 创建blob图片路径,赋值给裁剪cropper的option.img显示,用于图片裁剪
                    this.option.img = URL.createObjectURL(file);
                } else { 
                    setTimeout(()=>{
                        this.errorMessage = '上传图片大小不能超过 10MB';
                    },300)
                }
            } else {
                setTimeout(()=>{
                    this.errorMessage = '只能上传后缀为.jpg、.jpeg、.png的图片噢~';
                },300)
            }
        },

        //上传图片
        uploadImg() {
            let _this = this;
            let pic;
            this.$refs.cropper.getCropData( data => {    // 获取截图的 base64 数据
                pic = data.substring(23);   // 是23!!!!! 去掉头部的 “data:image/png;base64,”(包括base64后面的逗号)
                var url = "http://upload-z2.qiniup.com/putb64/" + this.fileSize(pic);
                // 方法1:axios上传
                axios.post(url,pic,{
                    headers: {
                        'Content-Type': 'application/octet-stream',
                        'Authorization': "UpToken " + this.qiniuToken
                    },
                    signature: 'yes'
                }).then(res => {
                    let imgInfo = {
                        data: res.data // 上传的截图在七牛云中保存的hash和key值
                    };
                }).catch(err => { })

                // 方法2:原生xhr上传
                // var xhr = new XMLHttpRequest();
                // xhr.open("POST", url, false);   // 最后一个参数用false
                // xhr.setRequestHeader("Content-Type", "application/octet-stream");
                // xhr.setRequestHeader("Authorization", "UpToken " + this.qiniuToken);
                // xhr.send(pic);
            });
        },
    },
}
</script>
  
<style scoped lang="less">
.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: 18px;
    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>
  

拓展:img标签展示base64图片

<img src="data:image/png;base64,base64码" alt="" />           // 静态数据
<img :src={`data:image/png;base64,${doctorDis}`} alt="" />    // 动态数据

扫描二维码关注公众号,回复: 14623638 查看本文章

猜你喜欢

转载自blog.csdn.net/m0_48571414/article/details/129123394
今日推荐