工作章 – 上传图片编辑头像

最近修改bug,测试提了一个优化:上传图片,然后对图片进行平移,放大缩小来调整做头像,因此记录一下整个开发过程的思路。

企业微信截图_16220842236267.png

image.png

整体思路:

上传图片,获取地址->
给到调整框(对图片进行放大缩小平移操作来确定头像)->
实时预览(获取调整后的图片)->
确定将调整后的地址回传

使用组件:vue-cropper

父组件(弹框)代码:

<script lang="tsx">
import { Component, Prop, Vue, Emit, Watch } from 'vue-property-decorator'
//引入子组件(图片裁剪功能)
import cropper from './cropper.vue'
import { EMessage,EavatarType,EavatarCutParam } from '@/views/userCenter/model'

import { stripscript } from '@/utils/util'

@Component({
    components:{
        cropper
    }
})
export default class AvatarCut extends Vue {
    /**
     * 个人信息表单
     * @param Object
     */
    avatarFile:any = null
    // 上传图片返回地址
    imgUrl = ''
    // 图片裁剪值,实时预览
    previews:any = {}

    beforeAvatarUpload(file:any){
        let _this = this;
        const isImage = file.type == EavatarType.PNG || file.type == EavatarType.JPG || file.type == EavatarType.JPEG;
        const isLt500KB = file.size <  EavatarCutParam.FILESIZE;
        if (!isImage) {
            this.$message.error(this.$t('userCenter.isavatarType'));
            return
        }
        if (!isLt500KB) {
            this.$message.error(this.$t('userCenter.isavatarSize'));
            return
        }
        var reader = new FileReader(); 
        //转base64
        reader.onload = function(e:any) {
            // 上传完成,将图片地址给到裁剪组件
            _this.imgUrl = e.target.result
        }
        reader.readAsDataURL(file);
        let fileName = stripscript(file.name)
        if(fileName != file.name){
            var renameFile = new File([file],fileName,{type:file.type})
            console.log(file)
            file = renameFile
            console.log(file)
        }
        this.avatarFile = file;
        return false;
    }

    @Emit()
    cutCanvas(base:any){
        return {avatarPerview:base,avatarFile:this.avatarFile}
    }
    // 实时监听裁剪结果,结果就是最后确定值
    realTime(data:any) {
        console.log('kkkkkkkkk',data)
        this.previews = data.data;
        this.cutCanvas(data.base)
    }
    render() {
        return (
            <div class="my-message-popup-content">
                <el-upload
                    class="upload-demo"
                    action="#"
                    before-upload={this.beforeAvatarUpload}
                    accept="image/jpeg,image/png,image/jpg"
                    on-preview="handlePreview"
                    list-type="picture"
                    show-file-list={false}>
                    <el-button type="primary">{this.$t('userCenter.uploadAvatars')}</el-button>
                    <div slot="tip" class="el-upload__tip">{this.$t('userCenter.uploadLimit')}</div>
                </el-upload>
                <div class="content-file">
                    <div class="file-canvas">
                        <cropper props={{url:this.imgUrl}} onrealTime={this.realTime} ref='cropper'></cropper>
                    </div>
                    <div class="file-preview">
                        <div class="preview-title">{this.$t('userCenter.perviewAvatars')}</div>
                        <div class="preview-avatar">
                            <div style={this.previews.div} class="preview">
                                <img src={this.previews.url?this.previews.url: require('@/assets/images/head_default.svg')} style={this.previews.img}/>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}
</script>
<style lang="less" scoped>
.my-message-popup-content{
    padding:20px 0 20px 0px;
    .upload-demo{
            height: 36px;
        display: flex;
        .el-upload__tip{
            line-height: 36px;
            margin-top: 0;
            margin-left: 14px;
            color: #999999;
        }
        /deep/ .el-button{
            width: 104px;
            height: 38px;
            background: #2255B9;
            border-radius: 0;
        }
    }
    .content-file{
        width: 100%;
        height: 208px;
        margin-top: 20px;
        margin-bottom: 40px;
        display: flex;
        .file-canvas{
            width: 322px;
            height: 100%;
            position: relative;
            border: 1px solid #F1F1F1;
            .file-shade{
                position: absolute;
                width: 100%;
                height: 100%;
                top: 0;left: 0;
                z-index: 10;
                .file-shade-top,.file-shade-bottom{
                    width:100%;;background: #000; opacity: 0.6;
                }
                .file-shade-middle{
                    display: flex;
                    .file-shade-left,.file-shade-right{
                    height: 160px;background: #000; opacity: 0.6;
                    }
                    .file-cut{
                        width: 160px;
                        height: 160px;
                        border: 1px dashed #1890FF;
                        cursor: move;
                    }
                }
            }
        }
        .file-preview{
            width: 168px;
            height: 100%;
            margin-left: 20px;
            border: 1px solid #F1F1F1;
            .preview-title{
                margin-top: 36px;
                color: #333333;
                line-height: 16px;
                width: 100%;
                text-align: center;
                //font-weight: 600;
                font-size: 16px;
            }
            .preview-avatar{
                width: 100%;
                height: 132px;
                margin-top:24px;
                text-align: center;
            }
        }
    }
    /deep/ .preview{
        width: 90px;
        height: 90px;
        margin: 0 auto;
        overflow: hidden;
        border-radius: 50%;
        img{
            width: 90px;
            height: 90px;
            z-index: -1;
        }
    }
    /deep/ .vue-cropper{
        background: #FFFFFF;
    }
}
</style>

复制代码

子组件(裁剪功能)代码

<template>
    <div>
        <vueCropper
            style="width:320px;height:206px"
            ref="cropper"
            :img='url'
            :autoCrop="options.autoCrop"
            :fixedBox="options.fixedBox"
            :canMoveBox="options.canMoveBox"
            :autoCropWidth="options.autoCropWidth"
            :autoCropHeight="options.autoCropHeight"
            :centerBox="options.centerBox"
            @realTime="realTime"
        ></vueCropper>
    </div>
</template>

<script>
import { VueCropper } from 'vue-cropper'
export default {
    name: 'cropper',
    components: {
        VueCropper
    },
    props:{
        url:{
            default:'',
            type:String
        }
    },
    data(){
        return{
            options: {
                autoCrop: true, //默认生成截图框
                fixedBox: true, //固定截图框大小
                canMoveBox: false, //截图框不能拖动
                centerBox: false, //截图框被限制在图片里面
                autoCropWidth:100,  //截图框宽度
                autoCropHeight:100, //截图框高度
            },
            previews:{}
        }
    },
    methods:{
        // 实时预览函数
        realTime(data){
            // 获取裁剪图片blob数据,可以直接用getCropData获取base64
            this.$refs.cropper.getCropBlob((blob)=>{
                this.blobToDataURL(blob,(base)=>{
                    this.$emit('realTime',{data,base})
                })
            })
        },
        // 将blob转换成base64
        blobToDataURL(blob, callback) {
            let a = new FileReader();
            a.onload = function (e) { callback(e.target.result); }
            a.readAsDataURL(blob);
        }
    }
}
</script>

<style scoped>

</style>
复制代码

效果

20210527-145208.gif

参考:
blog.csdn.net/qq_41107231…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享