编写小部件,以便通过单击文本名称并输入新名称来重命名文件。我没有找到任何现成的解决方案,也许你可以指点我一个?

这是我结束的地方,它不起作用:由于某种原因,只有最后一个输入框正在改变,第一个和第二个输入框没有被引用:

<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); 
                ...
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top