Custom JCrop: 多选框模式下的选框删除

问题描述:

JCrop是jQuery的一种用于图片剪裁、框选的插件,项目里用到了它。由于需要在一张图片上框出多个选框,所以传入JCrop的参数中的multi选项为true。现在的问题是,框过的选框无法取消(删除),这样对于修改选框个数的用户体验非常不好。如下图:

QesDesc1
单击确认按钮后,如下图:
QesDesc2

想实现的功能:选定某个选框,单击一个“取消”按钮,该选框就可以消除。

思路:

1、由于JCrop是提供multi:false(单选)模式的,即:只能存在单个选框,每次重新框选时,原有选框都会消失。所以JCrop内部一定存在消除选框的功能。
2、选中选框时,记录当前选框对象(即高亮的选框);
3、将JCrop内部的选框消除函数暴露出来,在外部调用该函数。

实现过程:

第一次实现:视觉上没有完全消除选框

关键代码:

注意:

  • 要把对取消按钮的事件绑定写在Jcrop的回调函数中,不然获取不到Jcrop的this对象。
  • 同确认按钮一样,取消按钮也使用了事件委托,因为这两个按钮是用JS动态添加的。
  • 使用call绑定暴露出来的函数的this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$('#toast_'+id).find('.toastImg').Jcrop({
bgOpacity: .35,
multi: true,
}, function(){
jcrop_api = this; //将Jcrop对象传递出来,以便后面在该对象上调用removeSelection函数
//=================框选删除====================
$('body').on('click', '.toastCancel button', function(event) {//单击“取消”按钮的绑定事件
var current = $('.jcrop-current'); //当前选中的div DOM元素
console.log('Jcrop this', jcrop_api);
if(current && jcrop_api){
var removeFunc = jcrop_api.removeSelection; //获取Jcrop中实现消除选框功能的函数
console.log('removeFunc', removeFunc);
removeFunc.call(jcrop_api, jcrop_api.ui.selection); //用call函数在选中选框(Selection对象)上调用暴露出来的removeSelection函数
}
});
});

JCrop 源代码相关部分:

其实源代码没有什么实质性修改,主要是要找到实现所需功能的函数:multi属性 -> requestDelete函数 -> deleteSelection函数 -> removeSelection函数,并获取其所需的this和参数sel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Jcrop API methods
$.extend(Jcrop.prototype,{
//...other functions
removeSelection: function(sel){
console.log('this in removeSelection: ', this); //该函数需要用到JCrop插件的this对象
console.log('sel in removeSelection: ', sel); //传入的参数是个Selection对象
var i, n = [], m = this.ui.multi;
for(var i=0;i<m.length;i++){
if (sel !== m[i])
n.push(m[i]);
else m[i].remove();
}
return this.ui.multi = n;
},
//...other functions
}

这样修改后,基本可以实现想要的功能,但是还有一个小bug:选中选框后单击取消按钮,该选框是可以正常消除,并且在目标图片页面也不会出现红色框选线。但是,单击取消按钮时,选中选框并没有完全消失,仍然有个像遮罩层一样的东西存在于页面:
first-try
通过Chrome Dev Tools的Element面板看出,该Selection区域四周的jcrop-shades仍然存在。
left
bottom
right
top

第二次实现:完善消除选框的样式:

对比源码中使用removeSelection函数的地方,在其之后又调用了refresh函数,猜测我的bug是因为这个函数没有调用的原因。这次直接调用Jcrop API method中的requestDelete函数。它包含了消除函数removeSelection和更新函数refresh

关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$('#toast_'+id).find('.toastImg').Jcrop({
bgOpacity: .35,
multi: true,
}, function(){
jcrop_api = this;
console.log('parent', this);
//框选删除
$('body').on('click', '.toastCancel button', function(event) {
var current = $('.jcrop-current');
console.log('Jcrop this', jcrop_api);
if(current && jcrop_api){
var requestDelete = jcrop_api.requestDelete;
console.log('requestDelete:', requestDelete);
requestDelete.call(jcrop_api); //关键
}
});
});

然后修改按钮样式,并删除源码中不需要的console.log,得到完美结果:
删除选框前:
second-try-before
删除选框后:
second-try-after

参考文档

Jcrop API overview

心得

  • 本来以为会很复杂的代码才能实现的功能,到最后竟然几行就搞定了。思路清晰挺重要的~
  • 准备实习面试的过程中call函数是常考的,这次终于把call函数调用用在了实际问题的解决中~
分享
0%