vue-cli结合Element-ui基于cropper.js封装vue实现图片裁剪组件功能
前端工作中,经常需要图片裁剪的场景,cropper.js
是一款优秀的前端插件,api十分丰富。
本文是在vue-cli项目下封装图片裁剪插件,效果图如下:
话不多说,看步骤吧。
第一步:准备开发环境
cropper.js是基于jquery的,所以要先安装jquery
执行命令:
npm install --save-dev jquery cropper
为webpack配置添加jquery的映射
修改webpack.base.conf.js
配置,添加标红的一行
第二步:新建图片裁剪组件
index.vue内容:
由于用了element-ui,其中布局就引用了element-ui的组件
template:
style:
/*@import "cropper/dist/cropper.css";*/
/*!
* Cropper v3.1.3
* https://github.com/fengyuanchen/cropper
*
* Copyright (c) 2014-2017 Chen Fengyuan
* Released under the MIT license
*
* Date: 2017-10-21T10:03:37.133Z
*/
.avatar-wrapper{
width: 100%;
height: 100%;
overflow: hidden;
}
.cropper-container {
direction: ltr;
font-size: 0;
line-height: 0;
position: relative;
-ms-touch-action: none;
touch-action: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.cropper-container img {/*Avoid margin top issue (Occur only when margin-top <= -height)
*/
display: block;
height: 100%;
image-orientation: 0deg;
max-height: none !important;
max-width: none !important;
min-height: 0 !important;
min-width: 0 !important;
width: 100%;
}
.cropper-wrap-
Box,.cropper-canvas,.cropper-drag-
Box,.cropper-crop-
Box,.cropper-modal {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
.cropper-wrap-
Box,.cropper-canvas {
overflow: hidden;
}
.cropper-drag-
Box {
background-color: #fff;
opacity: 0;
}
.cropper-modal {
background-color: #000;
opacity: .5;
}
.cropper-view-
Box {
display: block;
height: 100%;
outline-color: rgba(51,153,255,0.75);
outline: 1px solid #39f;
overflow: hidden;
width: 100%;
}
.cropper-dashed {
border: 0 dashed #eee;
display: block;
opacity: .5;
position: absolute;
}
.cropper-dashed.dashed-h {
border-bottom-width: 1px;
border-top-width: 1px;
height: 33.33333%;
left: 0;
top: 33.33333%;
width: 100%;
}
.cropper-dashed.dashed-v {
border-left-width: 1px;
border-right-width: 1px;
height: 100%;
left: 33.33333%;
top: 0;
width: 33.33333%;
}
.cropper-center {
display: block;
height: 0;
left: 50%;
opacity: .75;
position: absolute;
top: 50%;
width: 0;
}
.cropper-center:before,.cropper-center:after {
background-color: #eee;
content: ' ';
display: block;
position: absolute;
}
.cropper-center:before {
height: 1px;
left: -3px;
top: 0;
width: 7px;
}
.cropper-center:after {
height: 7px;
left: 0;
top: -3px;
width: 1px;
}
.cropper-face,.cropper-line,.cropper-point {
display: block;
height: 100%;
opacity: .1;
position: absolute;
width: 100%;
}
.cropper-face {
background-color: #fff;
left: 0;
top: 0;
}
.cropper-line {
background-color: #39f;
}
.cropper-line.line-e {
cursor: e-resize;
right: -3px;
top: 0;
width: 5px;
}
.cropper-line.line-n {
cursor: n-resize;
height: 5px;
left: 0;
top: -3px;
}
.cropper-line.line-w {
cursor: w-resize;
left: -3px;
top: 0;
width: 5px;
}
.cropper-line.line-s {
bottom: -3px;
cursor: s-resize;
height: 5px;
left: 0;
}
.cropper-point {
background-color: #39f;
height: 5px;
opacity: .75;
width: 5px;
}
.cropper-point.point-e {
cursor: e-resize;
margin-top: -3px;
right: -3px;
top: 50%;
}
.cropper-point.point-n {
cursor: n-resize;
left: 50%;
margin-left: -3px;
top: -3px;
}
.cropper-point.point-w {
cursor: w-resize;
left: -3px;
margin-top: -3px;
top: 50%;
}
.cropper-point.point-s {
bottom: -3px;
cursor: s-resize;
left: 50%;
margin-left: -3px;
}
.cropper-point.point-ne {
cursor: ne-resize;
right: -3px;
top: -3px;
}
.cropper-point.point-nw {
cursor: nw-resize;
left: -3px;
top: -3px;
}
.cropper-point.point-sw {
bottom: -3px;
cursor: sw-resize;
left: -3px;
}
.cropper-point.point-se {
bottom: -3px;
cursor: se-resize;
height: 20px;
opacity: 1;
right: -3px;
width: 20px;
}
@media (min-width: 768px) {
.cropper-point.point-se {
height: 15px;
width: 15px;
}
}
@media (min-width: 992px) {
.cropper-point.point-se {
height: 10px;
width: 10px;
}
}
@media (min-width: 1200px) {
.cropper-point.point-se {
height: 5px;
opacity: .75;
width: 5px;
}
}
.cropper-point.point-se:before {
background-color: #39f;
bottom: -50%;
content: ' ';
display: block;
height: 200%;
opacity: 0;
position: absolute;
right: -50%;
width: 200%;
}
.cropper-invisible {
opacity: 0;
}
.cropper-bg {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
}
.cropper-hide {
display: block;
height: 0;
position: absolute;
width: 0;
}
.cropper-hidden {
display: none !important;
}
.cropper-move {
cursor: move;
}
.cropper-crop {
cursor: crosshair;
}
.cropper-disabled .cropper-drag-
Box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point {
cursor: not-allowed;
}
.avatar-view {
display: block;
margin: 15% auto 5%;
height: 220px;
width: 220px;
border: 3px solid #fff;
border-radius: 5px;
Box-shadow: 0 0 5px rgba(0,.15);
cursor: pointer;
overflow: hidden;
}
.avatar-view img {
width: 100%;
}
.avatar-body {
padding-right: 15px;
padding-left: 15px;
}
.avatar-upload {
overflow: hidden;
}
.avatar-upload label {
display: block;
float: left;
clear: left;
width: 100px;
}
.avatar-upload input {
display: block;
margin-left: 110px;
}
.avatar-alert {
margin-top: 10px;
margin-bottom: 10px;
}
.avatar-wrapper {
height: 364px;
width: 100%;
margin-top: 15px;
Box-shadow: inset 0 0 5px rgba(0,.25);
background-color: #fcfcfc;
overflow: hidden;
}
.avatar-wrapper img {
display: block;
height: auto;
max-width: 100%;
}
.avatar-preview {
float: left;
margin-top: 15px;
margin-right: 15px;
border: 1px solid #eee;
border-radius: 4px;
background-color: #fff;
overflow: hidden;
}
.avatar-preview:hover {
border-color: #ccf;
Box-shadow: 0 0 5px rgba(0,.15);
}
.avatar-preview img {
width: 100%;
}
.avatar-preview-round{
border-radius: 50%;
}
.preview-lg {
height: 184px;
width: 184px;
margin-top: 15px;
}
.preview-md {
height: 100px;
width: 100px;
}
.preview-sm {
height: 50px;
width: 50px;
}
@media (min-width: 992px) {
.avatar-preview {
float: none;
}
}
.avatar-btns {
margin-top: 30px;
margin-bottom: 15px;
}
.avatar-btns .btn-group {
margin-right: 5px;
}
script:
import $ from 'jquery'
import 'cropper/dist/cropper.js'
export default {
props:{
id:String
},data(){
return {
$container:null,$avatarView:null,$avatarModal : null,$loading : null,$avatarForm : null,$avatarUpload : null,$avatarSrc : null,$avatarData : null,$avatarInput : null,$avatarSave: null,$avatarBtns : null,$avatarWrapper : null,$avatarPreview: null,support: {
fileList: !!$('
').attr({
name: target,src: ''
});
var _this = this;
// Ready ifrmae
$iframe.one('load',function () {
// respond response
$iframe.on('load',function () {
var data;
try {
data = $(this).contents().find('body').text();
} catch (e) {
console.log(e.message);
}
if (data) {
try {
data = $.parseJSON(data);
} catch (e) {
console.log(e.message);
}
_this.submitDone(data);
} else {
}
_this.submitEnd();
});
});
this.$iframe = $iframe;
this.$avatarForm.attr('target',target).after($iframe.hide());
},click:function () {
this.initPreview();
},change: function () {
var files;
var file;
if (this.support.datauri) {
files = this.$avatarInput.prop('files');
if (files.length > 0) {
file = files[0];
if (this.isImageFile(file)) {
if (this.url) {
URL.revokeObjectURL(this.url); // Revoke the old one
}
this.url = URL.createObjectURL(file);
this.startCropper();
}
}
} else {
file = this.$avatarInput.val();
if (this.isImageFile(file)) {
this.syncUpload();
}
}
},//裁剪提交
submit: function () {
if (!this.$avatarSrc.val() && !this.$avatarInput.val()) {
return false;
}
if (this.support.formData) {
this.ajaxUpload();
return false;
}
},//旋转事件
rotate: function (e) {
var data;
if (this.active) {
data = $(e.target).data();
if (data.method) {
this.$img.cropper(data.method,data.option);
}
}
},isImageFile: function (file) {
if (file.type) {
return /^image\/\w+$/.test(file.type);
} else {
return /\.(jpg|jpeg|png|gif)$/.test(file);
}
},startCropper: function () {
var _this = this;
if (this.active) {
this.$img.cropper('replace',this.url);
} else {
this.$img = $('
viewmode:1,aspectRatio: 1,preview: this.$avatarPreview,restore:false,crop: function (e) {
var json = [
'{"x":' + e.x,'"y":' + e.y,'"height":' + e.height,'"width":' + e.width,'"rotate":' + e.rotate + '}'
].join();
//裁图参数存起来
_this.$avatarData.val(json);
}
});
this.active = true;
}
},stopCropper: function () {
if (this.active) {
this.$img.cropper('destroy');
this.$img.remove();
this.active = false;
}
},ajaxUpload: function () {
var url = '/oss/file/cropping';
var data = new FormData(this.$avatarForm[0]);
var _this = this;
$.ajax(url,{
type: 'post',data: data,dataType: 'json',processData: false,contentType: false,success: function (data,textStatus) {
_this.submitDone(data);
if(data.success){
//将返回的数据传给父组件
_this.$emit('cropper-success',data.data);
_this.cropDone();
}
},});
},syncUpload: function () {
this.$avatarSave.click();
},submitDone: function (data) {
if ($.isPlainObject(data) && data.state === 200) {
if (data.result) {
this.url = data.result;
if (this.support.datauri || this.uploaded) {
this.uploaded = false;
this.cropDone();
} else {
this.uploaded = true;
this.$avatarSrc.val(this.url);
this.startCropper();
}
this.$avatarInput.val('');
} else if (data.message) {
}
} else {
}
},cropDone: function () {
// this.$avatarForm.get(0).reset();
// this.$avatarSrc.prop('src',this.url);
this.stopCropper();
// this.$container.hide();
}
}
}
第三步:父组件引用子组件
用了element-ui中的 el-dialog组件,此时el-dialog组件为父组件
在父组件中引入子组件
template:
script:
调用子组件裁剪
方法
toCropper(){
this.$refs.cropper.submit();
},//子组件裁剪
方法成功执行后与父组件通信
cropperSuccessHandle(data){
//返回data
this.showCropper = false
this.avatarUrl2 = data.url
}
}
}
本文结合element-ui,vue-cli,jquery,cropper.js,实现裁图组件的封装,先写到这啦,如果对你有帮助,还请点个赞噢!
原文链接:https://www.f2er.com/vue/33459.html