上传图片裁剪插件(基于cropper.js的封装)

如题,这样的功能在开发中是非常常见的,cropper.js是一款很好的工具,网上都有详细的介绍,这篇文章提示很多友好的API和事件cropper.js 裁剪图片并上传(文档翻译+demo)

cropper.js需要借助jquery来实现,所以我这里的样式抄袭了jquery头像上传剪裁插件cropper这个工具,具体功能没有copy,只是觉得这一款界面符合用户体验,可以实时看到自己的裁剪效果(利用css3特性)

不多说上代码,样式上我用scss写的,反正最终是webpack打包的^_^,不支持ie9以下

html主要代码
<div class="update-bg" id="J-update-wrapper">
    <input type="file" id="J-update-img-file" style="display: none">
    <div class="update-wrapper">
        <div class="update-header clearfix">
            <h3 class="text">上传图片</h3>
            <button class="btn close J-close">x</button>
        </div>
        <div class="update-main">
            <button class="btn update-btn J-update-btn">请选择图片</button>
            <div class="update-body clearfix">
                <div class="body-left">
                    <img id="J-update-img" class="update-img" src="" alt="">
                </div>
                <div class="body-right">
                    <img src="" class="user-header" id="J-update-user-header">
                </div>
            </div>
            <div class="operation-wrapper clearfix">
                <div class="operation-left">
                    <div class="left-container">
                        <button class="btn J-operation-btn" data-type="rote-left">向左旋转</button>
                        <button class="btn J-operation-btn" data-type="rote-right">向右旋转</button>
                    </div>
                    <div class="right-container">
                        <button class="btn J-operation-btn" data-type="scale-b">放大</button>
                        <button class="btn J-operation-btn" data-type="scale-s">缩小</button>
                    </div>
                </div>
                <div class="operation-right">
                    <button class="btn J-operation-save">保存图片</button>
                </div>
            </div>
        </div>
    </div>
</div>
scss代码
// 主色调
$btnColor: $basic_color;
.update-bg {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    background-color: rgba(0, 0, 0, .7);
    display: none;
    z-index: 999;
    .btn {
        display: inline-block;
        text-align: center;
        vertical-align: middle;
        touch-action: manipulation;
        cursor: pointer;
        padding: 6px 12px;
        background: transparent;
        border: 0;
        border-radius: 4px;
    }
    .clearfix:after {
        display: block;
        content: '';
        clear: both;
    }
    .update-wrapper {
        position: relative;
        margin: 50px auto;
        width: 900px;
        min-height: 580px;
        background-color: #fff;
        border: 1px solid rgba(0, 0, 0, .2);
        box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
        border-radius: 6px;
        .update-header {
            padding: 15px;
            min-height: 20px;
            border-bottom: 1px solid #e5e5e5;
            .text {
                font-size: 18px;
                font-weight: 500;
                float: left;
            }
            .close {
                float: right;
                padding: 0;
                font-size: 22px;
                color: #000;
                text-shadow: 0 1px 0 #fff;
                font-weight: bold;
                opacity: .2;
            }
        }
        .update-main {
            padding: 15px 30px;
            .update-btn {
                height: 35px;
                background-color: $btnColor;
                border: $btnColor;
                color: #fff;
            }
            .update-body {
                margin-top: 15px;                    
                .body-left {
                    float: left;
                    width: 620px;
                    height: 360px;
                    box-shadow: inset 0 0 5px rgba(0,0,0,.25);
                    background-color: #fcfcfc;
                    overflow: hidden;
                    .update-img {
                        display: none;
                        width: 0;
                        height: 0;
                    }
                }
                .body-right {
                    float: right;
                    width: 180px;
                    height: 180px;
                    border: 1px solid #eee;
                    border-radius: 4px;
                    background-color: #fff;
                    overflow: hidden;
                    .user-header {
                        display: none;
                        max-width: none;
                        height: auto;
                    }
                }
            }
            .operation-wrapper {
                margin-top: 15px;      
                .operation-left {
                    float: left;
                    width: 620px;
                    .btn {
                        height: 35px;
                        background-color: $btnColor;
                        border: $btnColor;
                        color: #fff;
                    }
                    .left-container {
                        float: left;
                        .btn {
                            margin-right: 10px;
                        }
                    }
                    .right-container {
                        float: right;
                        .btn {
                            margin-left: 10px;
                        }
                    }
                }
                .operation-right {
                    float: right;
                    width: 180px;
                    .btn {
                        width: 100%;
                        height: 35px;
                        background-color: $btnColor;
                        border: $btnColor;
                        color: #fff;
                    }
                }
            }
        }
    }
}
js部分
// 重置样式
import 'common/style/reset.styl';
import './index.scss';
// cropper引入 样式和js文件都需要哦
import '../../../node_modules/cropper/dist/cropper.min.css';
import '../../../node_modules/cropper/dist/cropper.min.js';
// 保存上传图片的信息
const imgInfo = {
    width: null,
    height: null,
    rotate: 0
};
// 哨兵变量 对按钮的响应作判断
let cropperIng;
// jq对象 cropper的宿主
let cropperTarget;
// jq对象 裁剪实时呈现的效果图像
let userImg;
// 裁剪图片功能封装类
export default class UpdateCropper {
    // 回调方法
    constructor(callBack) {
        this.callBack = callBack;
    }
    // 初始化
    init() {
        imgInfo.width = null;
        imgInfo.height = null;
        imgInfo.rotate = 0;
        imgInfo.scale = 1;
        cropperIng = false;
        cropperTarget = $('#J-update-img');
        userImg = $('#J-update-user-header');
        $('#J-update-wrapper').fadeIn('slow');
        this.addEvent();
    }
    // 添加事件
    addEvent() {
        const _this = this;
        $('#J-update-img-file').on('change', function (e) {
            // 这样的操作不支持ie9及以下
            if (!this.files[0].type.match(/image.*/)) {
                alert('请选择正确的图片!');
            }
            const imgSrc = URL.createObjectURL(this.files[0]);
            _this.createCropper(imgSrc);
        });
        $('#J-update-wrapper').on('click', '.J-close', () => {
            this.destroy();
        });
        $('#J-update-wrapper').on('click', '.J-update-btn', function() {
            document.getElementById('J-update-img-file').click();
        });
        // 操作按钮
        $('#J-update-wrapper').on('click', '.J-operation-btn', function() {
            _this.operation($(this));
        });
        $('#J-update-wrapper').on('click', '.J-operation-save', () => {
            this.getCroppedCanvas();
        });
        // J-close
    }
    // 销毁
    destroy() {
        this.removeEvent();
        cropperTarget.cropper('destroy');
        userImg.attr('src', '').hide();
        cropperTarget.attr('src', '').hide();
        $('#J-update-wrapper').fadeOut('slow');
        // $('#J-update-wrapper').hide();
    }
    // 移除事件
    removeEvent() {
        $('#J-update-img-file').off();
        $('#J-update-wrapper').off();
    }
    /**
     * 创建cropper容器 巴拉巴拉
     * @param {string} src 
     */
    createCropper(src) {
        document.getElementById('J-update-img').onload = () => {
            const elem = document.getElementById('J-update-img');
            // 获取图片真实宽高,用于后期比例计算
            imgInfo.width = elem.naturalWidth;
            imgInfo.height = elem.naturalHeight;
            userImg.attr('src', src).show();
            cropperIng = true;
            cropperTarget.cropper('destroy');
            cropperTarget.cropper({
                aspectRatio: 9 / 9,
                viewMode: 1,
                // 创建 用户操作都会改变显示对象
                crop: (e) => {
                    this.changeImg(e.detail);
                }
            });
        };
        cropperTarget.attr('src', src).show();
    }
    // 右侧显示对象改变
    changeImg(detail) {
        const num = 180 / detail.width;
        userImg.css({
            transform: `translate(-${detail.x * num}px, -${detail.y * num}px) rotate(${imgInfo.rotate}deg)`,
            width: `${imgInfo.width * num}px`,
            height: `${imgInfo.heigh * num}px`
        });
    }
    // 操作方法 旋转缩放都是在基于上一次操作的基础上
    operation(target) {
        if (!cropperIng) {
            return;
        }
        const type = target.data('type');
        switch (type) {
            // 左旋90case 'rote-left':
                imgInfo.rotate -= 90;
                $('#J-update-img').cropper('rotate', -90);
                break;
            // 右旋90case 'rote-right':
                imgInfo.rotate += 90;
                $('#J-update-img').cropper('rotate', 90);
                break;
            // 放大一下下
            case 'scale-b':
                $('#J-update-img').cropper('zoom', 0.1);
                break;
            case 'scale-s':
            // 缩小一下下
                $('#J-update-img').cropper('zoom', -0.1);
                break;
        }
    }
    // 转换成base64输出
    getCroppedCanvas() {
        if (!cropperIng) {
            return;
        }
        const cas = cropperTarget.cropper('getCroppedCanvas');
        const base64 = cas.toDataURL('image/jpeg');
        this.callBack(base64);
        this.destroy();
    }
}
演示一下效果(GIF图)

这里写图片描述

缩放,裁剪,旋转这些基本功能都全了,如果有兴趣可以拓展

github地址

项目github地址 大致思路就是这样,如果有其它功能就自行拓展吧~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值