如题,这样的功能在开发中是非常常见的,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) {
// 左旋90度
case 'rote-left':
imgInfo.rotate -= 90;
$('#J-update-img').cropper('rotate', -90);
break;
// 右旋90度
case '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地址 大致思路就是这样,如果有其它功能就自行拓展吧~