当在DOM中移动元素时,该元素是否保持状态?

时间:2014-12-01 20:00:33

标签: javascript

<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。 它确实如此。

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

谁能告诉我为什么?

3 个答案:

答案 0 :(得分:1)

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

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

JavaScript没有时间旅行。它不会撤消for循环所执行的操作并重新运行它们只是因为它们过去运行的数据从那时起已经发生了变化。


您应该通过使用单个事件处理函数来解决这个问题,该函数不是对from和to元素进行硬编码,而是根据this.parentNode的值进行处理。

答案 1 :(得分: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>

答案 2 :(得分:1)

问题是,第一个列表#task1中的复选框会在更改事件中移至列表#task2。在此之后以及随后的更改事件中,复选框仍然移动到同一列表,因为事件处理程序是相同的。这就是为什么您无法将复选框移回初始列表的原因。

要修复此问题,您可以编写一个函数,而不是两个moveFromTask1to2moveFromTask2to1。例如:

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

查看下面的演示。

&#13;
&#13;
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)
&#13;
<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>
&#13;
&#13;
&#13;