注意事项:需要引入jquery的图片裁剪插件--Jcrop
<script src="./assets/lib/Jcrop/js/jquery.Jcrop.min.js"></script>
1.实现效果图:

2.代码实现:
html部分:
<nz-modal
[(nzVisible)]="imageCropperVisible"
(nzOnCancel)="imageCropperVisible = false"
(nzAfterClose)="jcropModalClosed()"
(nzOnOk)="updateAvatar()"
[nzOkLoading]="modalOkLoading"
[nzKeyboard]="false"
[nzClosable]="false"
[nzMaskClosable]="false"
[nzWidth]="800"
>
<div class="jcrop-wrapper">
<div class="jcrop-main">
<!-- 上传的原图部分 -->
<div class="jcrop-target">
<img id="target" />
<span [ngStyle]="{ display: jcropLoaded ? 'none' : 'block' }">Loading...</span>
</div>
<!-- 预览图部分 -->
<div id="preview-pane" [ngStyle]="{ display: jcropLoaded ? 'block' : 'none' }">
<div class="preview-container">
<img class="jcrop-preview" />
</div>
</div>
</div>
</div>
</nz-modal>
js部分:
imageCropperVisible = false; // 是否展示弹窗
jcropApi: any = null;
jcropBound = {
x: 0,
y: 0,
};
jcropLoaded = false; // 图片加载loading
modalOkLoading = false; // 确认上传loading
private previewPane = null; // 预览图盒子
private previewImg = null; //预览图url
// 裁切图片的偏移量
private jcropData = {
w: 0,
h: 0,
x: 0,
y: 0,
};
const JCROP_CONFIG = {
aspectRatio: 0, // 选框宽高比。说明:width/height,默认值为0
size: 750,
boxWidth: 500,
boxHeight: 500,
};
/**
* 裁剪图片
* 在html传原图地址
*/
editIamge(url: any) {
this.imageCropperVisible = true; // 是否出现裁剪弹窗
this.imageUrl = environment.imageDomain + '/' + url; // 裁剪弹窗的底图
this.imagepath = url; // 裁剪图片的参数
setTimeout(() => {
this.initJcrop();
}, 500);
}
initJcrop() {
const _that = this;
this.previewPane = $('#preview-pane .preview-container');
this.previewImg = $('#preview-pane .preview-container img');
$('.jcrop-preview').attr('src', this.imageUrl);
let jcropInit = false;
const { boxWidth, boxHeight, aspectRatio } = JCROP_CONFIG;
$('#target').Jcrop(
{
onChange: this.updatePreview,
onSelect: this.updatePreview,
boxWidth,
boxHeight,
aspectRatio,
allowSelect: false,
minSize: [100, 100],
},
// 不可使用箭头函数,否则无法获取真实的jcrop对象
function () {
_that.jcropApi = this;
this.setImage(_that.imageUrl, function () {
jcropInit = true;
const bounds = this.getBounds();
const [w, h] = bounds;
_that.jcropBound.x = w;
_that.jcropBound.y = h;
const x = w / 2 - JCROP_CONFIG.size;
const x2 = w / 2 + JCROP_CONFIG.size;
const y = h / 2 - JCROP_CONFIG.size;
const y2 = h / 2 + JCROP_CONFIG.size;
this.setSelect([x, y, x2, y2]);
this.animateTo([x, y, x2, y2]);
});
},
);
}
// 设置预览
updatePreview = (c) => {
this.jcropLoaded = true;
if (parseInt(c.w) > 0) {
const rx = this.previewPane.width() / c.w;
const ry = this.previewPane.height() / c.h;
this.previewImg.css({
width: Math.round(rx * this.jcropBound.x) + 'px',
height: Math.round(ry * this.jcropBound.y) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px',
});
}
const { x, y, w, h } = c;
this.jcropData = {
x,
y,
w,
h,
};
};
// 裁剪弹窗关闭
jcropModalClosed() {
if (this.jcropApi) {
this.jcropApi.destroy();
}
this.jcropApi = null;
this.jcropBound = {
x: 0,
y: 0,
};
this.imageUrl = '';
this.imagepath = '';
this.previewPane = null;
this.previewImg = null;
this.jcropLoaded = false;
}
// 裁切完图片上传
updateAvatar() {
this.modalOkLoading = true;
const { x, y, w, h } = this.jcropData;
const params = {
filePath: this.imagepath,
width: Math.round(w),
height: Math.round(h),
startX: Math.round(x),
startY: Math.round(y),
}
}