2014-12-01 48 views
1
<ul id="task1"> 
    <li><input type="checkbox" id="input1"><label>Item task1></label></li> 
    ... some other <li> go here 
</ul> 

<ul id="task2"> 
    <li><input type="checkbox"><label>Item task2></label></li> 
    ... 
</ul> 

var task1 = document.getElementById("task1"); 
var task2 = document.getElementById("task2"); 
var moveFromTask1to2 = function() { task2.appendChild(this.parentNode); } 
var moveFromTask2to1 = function() { task1.appendChild(this.parentNode); } 
var bindElement(listItem, task) { 
    var checkbox = listItem.querySelector("input[type=checkbox]"); 
    checkbox.onchange = task; 
} 

for (var i = 0; i < task1.children.length; i++) { bindElement(task1.children[i], moveFromTask1to2); //(1) 
for (var i = 0; i < task2.children.length; i++) { bindElement(task2.children[i], moveFromTask2to1); //(2) 

当我检查input1复选框时,它应该从task1移到task2。 它是这样做的。在DOM中移动元素时,该元素是否保持状态?

但是,当我再次检查input1复选框,它不会从task2迁回task1

谁能告诉我为什么?

+0

我已经得到了它。感谢所有人。 – user3071121 2014-12-01 20:32:55

回答

1

的问题是,从第一清单#task1复选框被移动到列表#task2更改事件。发生这种情况后,在后续的更改事件中,复选框仍会移至同一列表中,因为事件处理程序是相同的。这就是为什么你不能将复选框移回初始列表。

要修复它,你可以写一个函数而不是两个moveFromTask1to2moveFromTask2to1。例如:

var moveFromTo = function() { 
    var moveTo = this.parentNode.parentNode === task1 ? task2 : task1; 
    moveTo.appendChild(this.parentNode); 
}; 

查看下面的演示。

var task1 = document.getElementById("task1"); 
 
var task2 = document.getElementById("task2"); 
 

 
var moveFromTo = function() { 
 
    var moveTo = this.parentNode.parentNode === task1 ? task2 : task1; 
 
    moveTo.appendChild(this.parentNode); 
 
} 
 

 
var bindElement = function(listItem, task) { 
 
    var checkbox = listItem.querySelector("input[type=checkbox]"); 
 
    checkbox.onchange = task; 
 
} 
 

 
for (var i = 0; i < task1.children.length; i++) { bindElement(task1.children[i], moveFromTo); } //(1) 
 
for (var i = 0; i < task2.children.length; i++) { bindElement(task2.children[i], moveFromTo); } //(2)
<ul id="task1"> 
 
    <li> 
 
     <input type="checkbox" id="input1" /> 
 
     <label>Item task11></label> 
 
    </li> 
 
    <li> 
 
     <input type="checkbox" id="input1" /> 
 
     <label>Item task12></label> 
 
    </li> 
 
</ul> 
 
<ul id="task2"> 
 
    <li> 
 
     <input type="checkbox" /> 
 
     <label>Item task21></label> 
 
    </li> 
 
    <li> 
 
     <input type="checkbox" /> 
 
     <label>Item task22></label> 
 
    </li> 
 
</ul>

1

您将一个事件处理程序绑定到名为moveFromTask1to2的对象。

您的任何代码都不会删除该事件处理程序,并会添加moveFromTask2to1

JavaScript不会时间旅行。它不会撤消你的for循环所做的并重新运行它们,只是因为它们过去运行的数据从那以后发生了变化。


你或许应该使用一个单一的事件处理函数,而不是硬从和要素编码,作品出来的基础上this.parentNode价值解决这个问题。

+0

这是否意味着在DOM上移动元素时,即使将它添加到一组新状态,该元素也不会改变状态。我的意思是input1仍然绑定到moveFromTask1to2,即使我将它添加到task2,它的每个元素都有moveFromTask2to1事件处理程序 – user3071121 2014-12-01 20:19:37

+0

它改变* state *。 'parentNode'改变。它出现在DOM上的新位置。它不会更改事件处理程序绑定的事件。 – Quentin 2014-12-01 20:22:36

1

问题是,单击复选框时事件不会自动更改。它仍然有相同的事件处理程序,它将它从task1移动到task2。

解决方案1:

var moveFromTask1to2 = function() { 
    task2.appendChild(this.parentNode); 
    this.onchange = moveFromTask2to1; 
} 
var moveFromTask2to1 = function() { 
    task1.appendChild(this.parentNode); 
    this.onchange = moveFromTask1to2; 
} 

解决方案2:搬家后分配一个新的事件处理程序,使事件处理程序更通用的,所以它成为一个单一的 '切换' 功能:

var task1 = document.getElementById("task1"); 
 
var task2 = document.getElementById("task2"); 
 

 
var moveItem = function() { 
 
    var task = this.parentNode.parentNode; 
 
    if (task == task1) 
 
    task2.appendChild(this.parentNode); 
 
    else 
 
    task1.appendChild(this.parentNode); 
 
} 
 

 
var bindElement = function(listItem) { 
 
    var checkbox = listItem.querySelector("input[type=checkbox]"); 
 
    checkbox.onchange = moveItem; 
 
} 
 

 
for (var i = 0; i < task1.children.length; i++) { bindElement(task1.children[i]);} //(1) 
 
for (var i = 0; i < task2.children.length; i++) { bindElement(task2.children[i]);} //(2)
ul { 
 
    border: 1px solid blue; 
 
}
<ul id="task1"> 
 
    <li><input type="checkbox" id="input1"><label>Item task1></label></li> 
 
    
 
</ul> 
 

 
<ul id="task2"> 
 
    <li><input type="checkbox"><label>Item task2></label></li> 
 
    ... 
 
</ul>

虽然你会注意到,移动的作品,但状态(即'检查')被记住的复选框。你可以在代码中重置它,但实际上我认为从UX角度来看这是一个相当糟糕的解决方案。复选框用于检查/选择元素。它不应该什么。如果您希望能够将listitem移动到另一个列表中,则应该使用按钮。

虽然这并没有改变答案。如果您将复选框更改为按钮并使用onclick事件而不是onchange,则同样的答案适用。从技术上讲,它几乎与上面相同的片段,但是从用户的角度来看,这使得这么多的意义:

var task1 = document.getElementById("task1"); 
 
var task2 = document.getElementById("task2"); 
 

 
var moveItem = function() { 
 
    var task = this.parentNode.parentNode; 
 
    if (task == task1) 
 
    task2.appendChild(this.parentNode); 
 
    else 
 
    task1.appendChild(this.parentNode); 
 
} 
 

 
var bindElement = function(listItem) { 
 
    var button = listItem.querySelector("input[type=button]"); 
 
    button.onclick = moveItem; 
 
} 
 

 
for (var i = 0; i < task1.children.length; i++) { bindElement(task1.children[i]);} //(1) 
 
for (var i = 0; i < task2.children.length; i++) { bindElement(task2.children[i]);} //(2)
ul { 
 
    border: 1px solid blue; 
 
}
<ul id="task1"> 
 
    <li><input type="button" value="Move"/><label>Item task1></label></li> 
 
    
 
</ul> 
 

 
<ul id="task2"> 
 
    <li><input type="button" value="Move"><label>Item task2></label></li> 
 
    ... 
 
</ul>