为什么在测试ui.sender时jquery sortable中的更新事件似乎运行了两次
我正在使用jQueryUISortable对连接的列表进行排序。更新事件似乎运行了两次 以下是完整的可排序呼叫:为什么在测试ui.sender时jquery sortable中的更新事件似乎运行了两次,jquery,jquery-ui-sortable,Jquery,Jquery Ui Sortable,我正在使用jQueryUISortable对连接的列表进行排序。更新事件似乎运行了两次 以下是完整的可排序呼叫: $(".pageContent").sortable({ handle: ".quesText", connectWith: ".pageContent", containment: "section", start: function(e, ui){ ui.placeholder.height(ui.item.height());
$(".pageContent").sortable({
handle: ".quesText",
connectWith: ".pageContent",
containment: "section",
start: function(e, ui){
ui.placeholder.height(ui.item.height());
},
placeholder: "sortable-placeholder",
opacity: 0.5,
cursor: "move",
cancel: "input, select, button, a, .openClose",
update: function(e, ui){
var thisItem = ui.item;
var next = ui.item.next();
var prev = ui.item.prev();
var thisNumber = thisItem.find(".quesNumb");
var nextNumber = next.find(".quesNumb");
var prevNumber = prev.find(".quesNumb");
var tn = parseInt(thisNumber.text());
var nn = parseInt(nextNumber.text());
var pn = parseInt(prevNumber.text());
var quesNumbs = $(".quesNumb");
var newItemId = thisItem.attr("id").replace(/_\d+$/, "_");
//test if we are dragging top down
if(ui.position.top > ui.originalPosition.top){
quesNumbs.each(function(i){
var thisVal = parseInt($(this).text());
var grandparent = $(this).parent().parent();
var grandId = grandparent.attr("id").replace(/_\d+$/, "_");
if(thisVal > tn && (thisVal <= pn || thisVal <= (nn - 1))){
$(this).text(thisVal - 1 + ".");
grandparent.attr("id",grandId + (thisVal - 1));
}
});
if(!isNaN(pn) || !isNaN(nn)){
if(!isNaN(pn)){
//for some reason when there is a sender pn gets updated, so we check if sender exists
//only occurs sorting top down
if($.type(ui.sender) !== "null"){
var senderId = ui.sender.attr("id");
thisNumber.text(pn + 1 + ".");
thisItem.attr("id",senderId + "_" + (pn + 1));
alert(thisItem.attr("id"));
}
else {
thisNumber.text(pn + ".");
thisItem.attr("id",newItemId + pn);
alert(thisItem.attr("id"));
}
}
else {
thisNumber.text(nn - 1 + ".");
}
}
else {
//something will happen here
}
}
//otherwise we are dragging bottom up
else {
quesNumbs.each(function(i){
var thisVal = parseInt($(this).text());
if(thisVal < tn && (thisVal >= nn || thisVal >= (pn + 1))){
$(this).text(thisVal + 1 + ".");
}
});
if(!isNaN(pn) || !isNaN(nn)){
if(!isNaN(pn)){
thisNumber.text(pn + 1 + ".");
}
else {
thisNumber.text(nn + ".");
}
}
else {
//something will happen here
}
}
}
});
我希望只有一个警报
作为ui。当排序停留在同一列表中时,发送者
为null
。当一个项目离开一个列表转到另一个列表时,ui.sender
将不再是null
问题是,当我将一个项目移动到新列表时,我将收到2警报消息。就好像ui.sender是在更新函数运行一次之后设置的,然后它会再次运行更新函数。显然,这是不好的,因为我正在覆盖不一定要覆盖的数据
如果是这样,我应该如何重写代码以避免覆盖数据
编辑
我相信每次更改列表DOM时都会调用更新事件,而不仅仅是在一般情况下更改DOM。因此,对于每个具有DOM更改的列表,更新都会运行。当我将一个项目移动到一个新列表时,我正在更新两个列表
所以我想新的问题是:如果知道这段代码会触发两次,我如何重写它?是否有接收和删除事件的组合可以实现这一点?我对每个可排序事件进行了一些调查。以下是我的发现,按发生顺序列出:
$(".pageContent").sortable({
start: function(e,ui){
//Before all other events
//Only occurs once each time sorting begins
},
activate: function(e,ui){
//After the start event and before all other events
//Occurs once for each connected list each time sorting begins
},
change: function(e,ui){
//After start/active but before over/sort/out events
//Occurs every time the item position changes
//Does not occur when item is outside of a connected list
},
over: function(e,ui){
//After change but before sort/out events
//Occurs while the item is hovering over a connected list
},
sort: function(e,ui){
//After over but before out event
//Occurs during sorting
//Does not matter if the item is outside of a connected list or not
},
out: function(e,ui){
//This one is unique
//After sort event before all drop/ending events unless **see NOTE
//Occurs, only once, the moment an item leaves a connected list
//NOTE: Occurs again when the item is dropped/sorting stops
//--> EVEN IF the item never left the list
//--> Called just before the stop event but after all other ending events
},
beforeStop: function(e,ui){
//Before all other ending events: update,remove,receive,deactivate,stop
//Occurs only once at the last possible moment before sorting stops
},
remove: function(e,ui){
//After beforeStop and before all other ending events
//Occurs only once when an item is removed from a list
},
receive: function(e,ui){
//After remove and before all other ending events
//Occurs only once when an item is added to a list
},
update: function(e,ui){
//After receive and before all other ending events
//Occurs when the DOM changes for each connected list
//This can fire twice because two lists can change (remove from one
//list but add to another)
},
deactivate: function(e,ui){
//After all other events but before out (kinda) and stop
//Occurs once for each connected list each time sorting ends
},
stop: function(e,ui){
//After all other events
//Occurs only once when sorting ends
}
});
在解决我的问题时,我只是强制更新函数的内容只运行一次,方法是将其包装在检查
ui.sender
的if-else
语句中。基本上它说如果ui.sender
不存在,那么这是第一次使用更新功能,我们应该执行该功能,否则什么也不做。我在这里发布了答案:
您可以组合remove和receive,并创建一个数组,该数组将保存更改,然后将其作为JSON发布到服务器
演示:
HTML:
第一步
图10
图11
图12
步骤2
图21
图22
图23
JS:
$(函数(){
/*我们将在这里存储所有数据*/
var myArguments={};
函数assembleData(对象、参数)
{
var data=$(object.sortable('toArray');//获取数组数据
var step_id=$(object.attr(“id”);//获取step_id并将其用作属性名
var arrayLength=data.length;//无需解释
/*如果步骤id属性不存在,请创建该属性*/
if(!arguments.hasOwnProperty(步骤id))
{
参数[步骤id]=新数组();
}
/*循环浏览所有项目*/
对于(变量i=0;i
解决方案的完整说明:
很抱歉,但我认为您的事件顺序中至少存在一个小问题:
停止
不是最后一个事件,而是更新
。如果我查看as引用来备份我,很明显,stop
事件发生在排序结束时,而update
事件发生在排序已结束且DOM已更改时。。。所以update
将在stop
之后发生,这样做很合乎逻辑,你不这么认为吗?@chool谢谢你提供了更有意义的信息。但我在这里得到的信息是通过我对每个事件的测试得到的。我通过在触发该事件时调用console.log(“无论该事件是什么”)进行测试。我的发现是更新事件在停止事件之前发送到日志中。源代码从不说谎:-停止事件是最后一个事件非常感谢,我尝试找到了发生这种情况的原因,并最终用您建议的解决方案解决了它。
$(".pageContent").sortable({
start: function(e,ui){
//Before all other events
//Only occurs once each time sorting begins
},
activate: function(e,ui){
//After the start event and before all other events
//Occurs once for each connected list each time sorting begins
},
change: function(e,ui){
//After start/active but before over/sort/out events
//Occurs every time the item position changes
//Does not occur when item is outside of a connected list
},
over: function(e,ui){
//After change but before sort/out events
//Occurs while the item is hovering over a connected list
},
sort: function(e,ui){
//After over but before out event
//Occurs during sorting
//Does not matter if the item is outside of a connected list or not
},
out: function(e,ui){
//This one is unique
//After sort event before all drop/ending events unless **see NOTE
//Occurs, only once, the moment an item leaves a connected list
//NOTE: Occurs again when the item is dropped/sorting stops
//--> EVEN IF the item never left the list
//--> Called just before the stop event but after all other ending events
},
beforeStop: function(e,ui){
//Before all other ending events: update,remove,receive,deactivate,stop
//Occurs only once at the last possible moment before sorting stops
},
remove: function(e,ui){
//After beforeStop and before all other ending events
//Occurs only once when an item is removed from a list
},
receive: function(e,ui){
//After remove and before all other ending events
//Occurs only once when an item is added to a list
},
update: function(e,ui){
//After receive and before all other ending events
//Occurs when the DOM changes for each connected list
//This can fire twice because two lists can change (remove from one
//list but add to another)
},
deactivate: function(e,ui){
//After all other events but before out (kinda) and stop
//Occurs once for each connected list each time sorting ends
},
stop: function(e,ui){
//After all other events
//Occurs only once when sorting ends
}
});
<div class="container">
<div class="step" id="step_1">
<h2 class="title">Step 1</h2>
<div class="image" id="image_10">Image 10</div>
<div class="image" id="image_11">Image 11</div>
<div class="image" id="image_12">Image 12</div>
</div>
<div class="step" id="step_2">
<h2 class="title">Step 2</h2>
<div class="image" id="image_21">Image 21</div>
<div class="image" id="image_22">Image 22</div>
<div class="image" id="image_23">Image 23</div>
</div>
$(function(){
/* Here we will store all data */
var myArguments = {};
function assembleData(object,arguments)
{
var data = $(object).sortable('toArray'); // Get array data
var step_id = $(object).attr("id"); // Get step_id and we will use it as property name
var arrayLength = data.length; // no need to explain
/* Create step_id property if it does not exist */
if(!arguments.hasOwnProperty(step_id))
{
arguments[step_id] = new Array();
}
/* Loop through all items */
for (var i = 0; i < arrayLength; i++)
{
var image_id = data[i];
/* push all image_id onto property step_id (which is an array) */
arguments[step_id].push(image_id);
}
return arguments;
}
/* Sort images */
$('.step').sortable({
connectWith: '.step',
items : ':not(.title)',
/* That's fired first */
start : function( event, ui ) {
myArguments = {}; /* Reset the array*/
},
/* That's fired second */
remove : function( event, ui ) {
/* Get array of items in the list where we removed the item */
myArguments = assembleData(this,myArguments);
},
/* That's fired thrird */
receive : function( event, ui ) {
/* Get array of items where we added a new item */
myArguments = assembleData(this,myArguments);
},
update: function(e,ui) {
if (this === ui.item.parent()[0]) {
/* In case the change occures in the same container */
if (ui.sender == null) {
myArguments = assembleData(this,myArguments);
}
}
},
/* That's fired last */
stop : function( event, ui ) {
/* Send JSON to the server */
$("#result").html("Send JSON to the server:<pre>"+JSON.stringify(myArguments)+"</pre>");
},
});
});