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 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);
...