VUE中头像裁剪上传到服务器

在项目遇到了如题所述的需求,很是折腾了一番。毕竟写前端和移动端native是不一样的!!现在进入正题,把dom部分摆出来:

    <div>
        <vueCropper style="width: 90%;height: 260px;margin-left: 5%;margin-top: 15px"
                    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"></vueCropper>
        <input style="margin-left: 20px;margin-top: 15px" id="file_input" type="file" capture="camera"/>
        <div class="btn" @click="compressImg()">上传头像</div>
    </div>

可以看到,在dom中我们使用了vueCropper这个组件。这个是今天的主角,图片裁剪控件。上github:

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

安装:$:npm install vue-cropper -s

vue-cropper组件的属性:

名称功能默认值可选值
img裁剪图片的地址url 地址 || base64 || blob
outputSize裁剪生成图片的质量10.1 - 1
outputType裁剪生成图片的格式jpg (jpg 需要传入jpeg)jpeg || png || webp
info裁剪框的大小信息truetrue || false
canScale图片是否允许滚轮缩放truetrue || false
autoCrop是否默认生成截图框falsetrue || false
autoCropWidth默认生成截图框宽度容器的80%0~max
autoCropHeight默认生成截图框高度容器的80%0~max
fixed是否开启截图框宽高固定比例truetrue | false
fixedNumber截图框的宽高比例[1 : 1][宽度 : 高度]
full是否输出原图比例的截图falsetrue | false
fixedBox固定截图框大小 不允许改变falsetrue | false
canMove上传图片是否可以移动truetrue | false
canMoveBox截图框能否拖动truetrue | false
original上传图片按照原始比例渲染falsetrue | false
centerBox截图框是否被限制在图片里面falsetrue | false
high是否按照设备的dpr 输出等比例图片truetrue | false
infoTruetrue 为展示真实输出图片宽高 false 展示看到的截图框宽高falsetrue | false
maxImgSize限制图片最大宽度和高度20000-max

内置方法通过this.$refs.cropper 调用:

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度

图片加载的回调 imgLoad 返回结果success, error

// 获取截图的base64 数据
this.$refs.cropper.getCropData((data) => {
  // do something
  console.log(data)  
})

// 获取截图的blob数据
this.$refs.cropper.getCropBlob((data) => {
  // do something
  console.log(data)  
})

好了,vue-cropper就介绍到这里。详细的可以去github里面看。

现在我们看看 input type='file' 通过Input我们可以得到选择的图片,直接放入vueCropper中来:

 mounted(){
            let _self = this;
            $("input[type='file']").change(function(){
                Indicator.open();
                let file = this.files[0];
                if (window.FileReader) {
                    let reader = new FileReader();
                    reader.readAsDataURL(file);
                    //监听文件读取结束后事件    
                    reader.onloadend = function (e) {
                        _self.option.img = e.target.result;
                        Indicator.close();
                    };
                }
            });
        },

这里使用jquery来获取选取的图片,而且要放在mounted()生命周期钩子中。不能放入之前的生命的钩子中。

现在调用裁剪方法:

compressImg:function () {
                let _self = this;
                this.$refs.cropper.startCrop();
                this.$refs.cropper.getCropData((data) => {
                    let file = _self.convertBase64UrlToBlob(data);
                    file.name = 'head.jpg';
                    _self.uploadAction(file);
                })
            },

这里我们用得到的BASE64数据转换成Blob数据,直接把Blob当做file来这里,不要忘记设置file.name。不然上传文件的时候是会出错的!!得到数据之后,就开始上传了,调用你自己的ajax方法吧!这里我们使用axios来做图片上传:

  uploadAction:function (file) {
                Indicator.open();
                let _self = this;
                let param = new FormData();  // 创建form对象
                param.append('pics', file, file.name);  // 通过append向form对象添加数据
                let config = {
                    headers: {'Content-Type': 'multipart/form-data'}
                };
                // 添加请求头
                this.$axios.post('/appapi/user/i/up-headimg/pics', param, config)
                    .then(response => {
                      if(response.status == 200){
                          let data = response.data;
                          Indicator.close();
                         //出来服务器的返回数据
                      }
                    })
                    .catch(error=>{
                        Indicator.close();
                        console.log(error);
                    })
            },

完整代码如下:

​
<template>
    <div>
        <vueCropper style="width: 90%;height: 260px;margin-left: 5%;margin-top: 15px"
                    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"></vueCropper>
        <input style="margin-left: 20px;margin-top: 15px" id="file_input" type="file" capture="camera"/>
        <div class="btn" @click="compressImg()">上传头像</div>
        <span>{{status}}</span>
    </div>
</template>

<script>
    import { MessageBox, Indicator,Toast,Actionsheet  } from "mint-ui";
    import $ from 'jquery'
    import VueCropper from "vue-cropper"
    export default {
        name: "ImageUpload",
        components:{
            VueCropper,
            MessageBox,
            Indicator,
            Toast,

        },
        mounted(){
            let _self = this;
            $("input[type='file']").change(function(){
                Indicator.open();
                let file = this.files[0];
                if (window.FileReader) {
                    let reader = new FileReader();
                    reader.readAsDataURL(file);
                    //监听文件读取结束后事件    
                    reader.onloadend = function (e) {
                        _self.option.img = e.target.result;
                        Indicator.close();
                    };
                }
            });
        },
        data(){
            return{
                option: {
                    img: "",                         //裁剪图片的地址
                    info: true,                      //裁剪框的大小信息
                    outputSize: 0.7,                   // 裁剪生成图片的质量
                    outputType: 'jpeg',              //裁剪生成图片的格式
                    canScale: true,                 // 图片是否允许滚轮缩放
                    autoCrop: true,                  // 是否默认生成截图框
                    autoCropWidth: 100,              // 默认生成截图框宽度
                    autoCropHeight: 100,             // 默认生成截图框高度
                    fixed: false,                    //是否开启截图框宽高固定比例
                    fixedNumber: [4, 4]              //截图框的宽高比例
                },
                status:'',
                headImg:''
            }
        },
        methods:{
            showToast:function (msg) {
                Toast({
                    message: msg,
                    position: 'bottom',
                    duration: 2000
                })
            },
            compressImg:function () {
                let _self = this;
                this.$refs.cropper.startCrop();
                this.$refs.cropper.getCropData((data) => {
                    let file = _self.convertBase64UrlToBlob(data);
                    file.name = 'head.jpg';
                    _self.uploadAction(file);
                })
            },
            uploadAction:function (file) {
                Indicator.open();
                let _self = this;
                let param = new FormData();  // 创建form对象
                param.append('pics', file, file.name);  // 通过append向form对象添加数据
                let config = {
                    headers: {'Content-Type': 'multipart/form-data'}
                };
                // 添加请求头
                this.$axios.post('/appapi/user/i/up-headimg/pics', param, config)
                    .then(response => {
                      if(response.status == 200){
                          let data = response.data;
                          Indicator.close();
                          //处理服务器返回数据
                      }
                    })
                    .catch(error=>{
                        Indicator.close();
                        console.log(error);
                    })
            },
            // 将base64的图片转换为file文件
            convertBase64UrlToBlob(urlData) {
                let bytes = window.atob(urlData.split(',')[1]);//去掉url的头,并转换为byte
                //处理异常,将ascii码小于0的转换为大于0
                let ab = new ArrayBuffer(bytes.length);
                let ia = new Uint8Array(ab);
                for (var i = 0; i < bytes.length; i++) {
                    ia[i] = bytes.charCodeAt(i);
                }
                return new Blob([ab], { type: 'image/jpeg' });
            },
           
        }
    }
</script>

<style scoped>
    .btn{
        width: 80%;
        height: 40px;
        margin-top: 50px;
        color: white;
        border-radius: 20px;
        background-color: #3377ff;
        display: flex;
        align-items: center;
        justify-content: center;
        margin-left: 10%;
    }
</style>

​

 

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值