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 Fifth Edition), 더 빠르고 효율적인 방법이 있습니다.

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-splace-editor 전에 필드를 편집합니다.

문제는 여기에 추가 된 청취자 기능이 발사되면 글로벌 변수 "체인저"에 대한 참조를 포함한다는 것입니다. 당시에는 루프가 이미 완료되었으므로 "체인저"는 루프의 마지막 항목을 가리 킵니다.

또한 청취자를 추가하는 것은 지저분한 크로스 브라우저가 될 수 있습니다. 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