2009-10-25 41 views
1

編寫一個窗口小部件,以便通過單擊文本名稱並輸入新名稱來重命名文件。我沒有找到任何現成的解決方案,也許你可以指給我一個?JavaScript中的通用點擊重命名腳本(文本到輸入/文本框)

這裏是我結束了和它不工作:出於某種原因,只有最後一個輸入框正在發生變化,第一和第二沒有被引用:

<span id="text_name_0">Hello, world. Click me please.</span> 
<input type="hidden" id="name_changer_0" /> 
<input type="hidden" id="done_changing_0" value="Done"/> 
<br/> 
<span id="text_name_1">Hello, world. Click me please.</span> 
<input type="hidden" id="name_changer_1" /> 
<input type="hidden" id="done_changing_1" value="Done"/> 
<br/> 
<span id="text_name_2">Hello, world. Click me please.</span> 
<input type="hidden" id="name_changer_2" /> 
<input type="hidden" id="done_changing_2" value="Done"/> 

<script type="text/javascript"> 

function TextChanger(id) { 
    this.textNode = document.getElementById('text_name_' + id); 
    this.textValue = this.textNode.firstChild.nodeValue; 
    this.textboxNode = document.getElementById('name_changer_' + id); 
    this.doneButton = document.getElementById('done_changing_' + id); 
} 

TextChanger.prototype.change = function(node) { 
      node.textboxNode.setAttribute('value', node.textValue); 
      node.textNode.style.display = 'none'; 
      node.textboxNode.setAttribute('type','text'); 
      node.doneButton.setAttribute('type','button'); 
} 

TextChanger.prototype.changeBack = function(node) { 
      node.textNode.firstChild.nodeValue = node.textboxNode.value; 
      node.textNode.style.display = 'block'; 
      node.textboxNode.setAttribute('type', 'hidden'); 
      node.doneButton.setAttribute('type','hidden'); 
} 

for (var i=0; i < 3; i++) { 
     changer = new TextChanger(i); 
     changer.textNode.addEventListener("click", function() { 
      changer.change(changer); 
     }, false); 

     changer.doneButton.addEventListener("click", function() { 
      changer.changeBack(changer); 
     }, false); 
} 
</script> 

感謝。

+0

這是禮貌的接受一個答案(點擊複選框),你可能也投了被證明有益或教你一些其他的答案。 – 2009-10-25 14:19:27

回答

1

這是一個典型的循環變量綁定問題。參見this question進行一些討論。

您的關閉是無效的,因爲它關閉了在循環內使用的changer的副本,循環將會改變。要綁定它,你需要另一種方式停止採取的當前版本的changer副本:(您可能更願意溝node說法,只是使用this

function changebind(c) { 
    return function() { 
     c.change(c); 
    }; 
} 

for (var i=0; i<3; i++) { 
    var changer= new TextChanger(i); 
    changer.textNode.addEventListener('click', changebind(changer), false); 

未來(ECMAScript中第五版),將有說這是一個更快和更有效的方式:

for (var i=0; i<3; i++) { 
    var changer= new TextChanger(i); 
    changer.textNode.addEventListener('click', changer.change.bind(changer), false); 
    changer.doneButton.addEventListener('click', changer.changeBack.bind(changer), false); 
} 

但在此期間,因爲大多數瀏覽器不支持function.bind的是,你可以破解,在這樣的:

if (!Object.bind) { 
    Function.prototype.bind= function(owner) { 
     var that= this; 
     var args= Array.prototype.slice.call(arguments, 1); 
     return function() { 
      return that.apply(owner, 
       args.length===0? arguments : arguments.length===0? args : 
       args.concat(Array.prototype.slice.call(arguments, 0)) 
      ); 
     }; 
    }; 
} 
+0

有道理,非常感謝! – 2009-10-26 17:01:24

0

如果你不介意jQuery的依賴關係,我已經使用jquery-in-place-editor來編輯之前的字段。

+0

謝謝 - 添加它,完美的作品 – 2009-10-25 06:07:40

0

問題是,當這裏添加的監聽器函數fire時,它們包含對全局變量「changer」的引用。當他們開火時,循環已經完成,所以「更換者」指向循環中的最後一個項目。

此外,添加監聽器可能會導致跨瀏覽器的混亂,使用像jQuery或YUI這樣的庫更安全。這也將使你傳遞一個對象給每個事件監聽器(一個跨瀏覽器的方式),因此,例如,你可以這樣做:

for (var i=0; i < 3; i++) { 
       var changer = new TextChanger(i); 
       YAHOO.util.Event.addListener(changer.textNode, "click", changer.change, changer); 
       ... 
+0

謝謝 - 現在我看到原因。 javascript正在使用'by-ref',而不是'按值'。 – 2009-10-25 06:08:48