17 of 17 menu

ข้อผิดพลาดจากการซ้ำซ้อนของฟังก์ชันสำหรับแก้ไของค์ประกอบ DOM ใน JavaScript

สมมติว่าเรามีรายการบางอย่าง:

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

ให้เราได้รายการและรายการย่อยของมัน มาเก็บในตัวแปรแยก:

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

ทำให้รายการย่อยในรายการของเรา สามารถแก้ไขได้ด้วยอินพุตที่ปรากฏขึ้น:

for (let li of lis) { li.addEventListener('click', function func() { let input = document.createElement('input'); input.value = li.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');

ทำให้เมื่ออินพุตเสียโฟกัส รายการใหม่ที่มีข้อความ ที่นำมาจากอินพุตของเราจะถูกเพิ่มเข้าไปในรายการ:

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 = li.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 = li.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 of 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); });

วิธีแก้ไขที่สาม

มีวิธีแก้ไขที่สง่างามกว่า คุณสามารถใช้ การมอบหมายเหตุการณ์ (Event Delegation) ในกรณีนี้ ปัญหากับรายการใหม่ในรายการ ก็จะไม่เกิดขึ้น:

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
เราใช้คุกกี้สำหรับการทำงานของเว็บไซต์ การวิเคราะห์ และการปรับเนื้อหาให้เหมาะสมส่วนบุคคล การประมวลผลข้อมูลเกิดขึ้นตาม นโยบายความเป็นส่วนตัว.
ยอมรับทั้งหมด ปรับแต่ง ปฏิเสธ