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 = 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');
Եկեք այնպես անենք, որ ինպուտի ֆոկուսի կորստի դեպքում ցուցակին ավելանա նոր կետ մեր ինպուտից վերցված տեքստով.
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);
});