2014-12-01 50 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>