Универсальный скрипт щелчка для переименования на JavaScript (текст для ввода / текстовое поле)

StackOverflow https://stackoverflow.com/questions/1619884

Вопрос

Написание виджета, позволяющего переименовывать файлы, щелкая по текстовому названию и вводя новое имя.Я не нашел никаких готовых к использованию решений, может быть, вы можете указать мне на одно из них?

Вот где я оказался, и это не работает:по какой-то причине меняется только последнее поле ввода, а на первое и второе нет ссылок:

<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 на месте чтобы отредактировать поля раньше.

Проблема в том, что когда функции прослушивателя, добавленные сюда, срабатывают, они содержат ссылки на глобальную переменную "changer".В момент их срабатывания цикл уже завершен, и поэтому "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