17 of 17 menu

JavaScript DOM 요소 편집 함수 중복 오류

다음과 같은 목록이 있다고 가정해 봅시다:

<ul> <li>1</li> <li>2</li> <li>3</li> </ul>

목록 자체와 그 항목들을 별도의 변수에 저장해 보겠습니다:

let ul = document.querySelector('ul'); let lis = document.querySelectorAll('li');

목록 항목을 나타나는 입력 필드(input)로 편집할 수 있도록 만들어 보겠습니다:

for (let li of lis) { li.addEventListener('click', function func() { let input = document.createElement('input'); input.value = list.textContent; li.textContent = ''; li.append(input); input.addEventListener('blur', function() { li.textContent = this.value; li.addEventListener('click', func); }); li.removeEventListener('click', func); }); }

이제 목록에 새로운 항목을 추가할 수 있기를 원한다고 가정해 봅시다. 이를 위해 목록 아래에 해당 입력 필드가 있다고 가정합니다:

<input id="adder">

이 입력 필드에 대한 참조를 변수에 저장하겠습니다:

let adder = document.querySelector('#adder');

입력 필드가 포커스를 잃을 때(blur) 입력 필드에서 가져온 텍스트를 가진 새 항목이 목록에 추가되도록 만들어 보겠습니다:

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; ul.append(li); });

이제 새로 추가된 항목들도 편집할 수 있기를 원한다고 가정해 봅시다. 항목 목록에 클릭 핸들러를 추가했을 때는 이 항목들이 아직 존재하지 않았기 때문에 자체적으로는 편집 기능이 작동하지 않을 것입니다.

이 문제를 해결할 수 있는 여러 가지 방법을 살펴보겠습니다.

첫 번째 해결책

가장 간단한 해결책은 func 함수의 코드를 복제하여 새로 생성된 항목에도 동일하게 적용하는 것입니다:

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; li.addEventListener('click', function func() { // 여기서 코드를 중복합니다 }); ul.append(li); });

물론, 이 해결책의 단점은 명확합니다. 코드를 중복하는 것은 올바르지 않습니다.

두 번째 해결책

중복 문제를 해결하기 위해 func 함수를 외부로 빼내어 함수 선언(Function Declaration)으로 만드는 것이 논리적입니다:

function func() { let input = document.createElement('input'); input.value = list.textContent; li.textContent = ''; li.append(input); input.addEventListener('blur', function() { li.textContent = this.value; li.addEventListener('click', func); }); li.removeEventListener('click', func); }

여기서 문제가 발생합니다. 문제는 우리의 함수가 외부 스코프에서 가져온 변수 li를 사용했다는 점입니다. 하지만 함수를 외부로 빼낸 후에는 이 변수가 보이지 않게 됩니다!

이 문제를 해결하기 위해 우리의 li를 매개변수로 전달하겠습니다:

function func(li) { let input = document.createElement('input'); input.value = list.textContent; li.textContent = ''; li.append(input); input.addEventListener('blur', function() { li.textContent = this.value; li.addEventListener('click', func); }); li.removeEventListener('click', func); }

그리고 여기서 우리의 해결책이 또 다른 문제를 야기합니다. 문제는 이벤트 핸들러에 매개변수를 간단히 전달할 수 없다는 점입니다:

for (let li in lis) { li.addEventListener('click', func(li)); // 작동하지 않습니다! }

이 문제를 해결하기 위해 익명 핸들러 내부에서 우리의 함수를 호출하면 됩니다:

for (let li of lis) { li.addEventListener('click', function() { func(li); }); }

그리고 새로운 목록 항목을 생성할 때도 비슷한 방식으로 처리하겠습니다:

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; li.addEventListener('click', function() { func(li); }); ul.append(li); });

세 번째 해결책

더 우아한 해결책이 존재합니다. 이벤트 위임을 활용하면 됩니다. 이 경우 새로운 목록 항목에 대한 문제가 발생하지 않습니다:

ul.addEventListener('click', function(event) { if (event.target.tagName === 'LI') { // 입력 필드가 아닌 li에 대한 클릭을 캐치합니다 let li = event.target; let input = document.createElement('input'); input.value = li.textContent; li.textContent = ''; li.append(input); input.addEventListener('blur', function() { li.textContent = this.value; }); } });

이 경우 목록 항목을 순회하는 루프가 전혀 필요하지 않으며, 새로운 목록 항목을 생성하는 코드는 다음과 같이 줄어들게 됩니다:

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; ul.append(li); });
한국어
AfrikaansAzərbaycanБългарскиবাংলাБеларускаяČeštinaDanskDeutschΕλληνικάEnglishEspañolEestiSuomiFrançaisहिन्दीMagyarՀայերենIndonesiaItaliano日本語ქართულიҚазақКыргызчаLietuviųLatviešuМакедонскиMelayuမြန်မာNederlandsNorskPolskiPortuguêsRomânăРусскийසිංහලSlovenčinaSlovenščinaShqipСрпскиSrpskiSvenskaKiswahiliТоҷикӣไทยTürkmenTürkçeЎзбекOʻzbekTiếng Việt
우리는 웹사이트 운영, 분석 및 개인화를 위해 쿠키를 사용합니다. 데이터 처리는 개인정보 처리방침에 따라 이루어집니다.
모두 수락 설정 거부