JavaScript中的通用点击重命名脚本(文本到输入/文本框)
-
06-07-2019 - |
题
编写小部件,以便通过单击文本名称并输入新名称来重命名文件。我没有找到任何现成的解决方案,也许你可以指点我一个?
这是我结束的地方,它不起作用:由于某种原因,只有最后一个输入框正在改变,第一个和第二个输入框没有被引用:
<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>
感谢。
解决方案
这是一个经典的循环变量绑定问题。有关讨论,请参见此问题。
你的闭包是无效的,因为它关闭了循环中使用的 changer
的副本,循环将改变。要绑定它,您需要另一个闭包来获取当前版本的 changer
的副本:
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);
(您可能更愿意抛弃 node
参数,只使用 this
。)
未来(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))
);
};
};
}
其他提示
如果你不介意jQuery依赖,我使用了 jquery-in-place-editor 之前编辑字段。
问题是当这里添加的侦听器函数触发时,它们包含对全局变量“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);
...
不隶属于 StackOverflow