2009-10-25 38 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