Koâplab hodisalar avtomatik ravishda brauzer tomonidan maâlum harakatlarni bajarishga olib keladi.
Masalan:
- Havolaga bosish â uning URL manziliga yoânaltiradi.
- Formani yuborish tugmasiga bosish â uni serverga yuborishni boshlaydi.
- Matn ustida sichqoncha tugmasini bosib uni siljitish â matnni tanlaydi.
Agar biz JavaScript-da hodisani qayta ishlasak, brauzerni mos harakatini xohlamasligimiz va oârniga boshqa xatti-harakatni amalga oshirishni xohlashimiz mumkin.
Brauzer harakatlarining oldini olish
Brauzerni harakat qilishini istamasligimizni aytishning ikki yoâli bor:
- Asosiy usul
eventobyektidan foydalanishdir.event.preventDefault()metodi mavjud. - Agar ishlov beruvchi
on<event>yordamida tayinlangan boâlsa (addEventListenerorqali emas), u holdafalseqaytarish ham bir xil ishlaydi.
Bu HTML kodida havolaga bosish yoânaltirish olib kelmaydi, brauzer hech narsa qilmaydi:
<a href="/" onclick="return false">Bu yerga bosing</a>
yoki
<a href="/" onclick="event.preventDefault()">bu yerga</a>
Keyingi misolda biz ushbu texnikadan JavaScript asosidagi menyu yaratish uchun foydalanamiz.
false qaytarish â istisnoHodisa ishlov beruvchisi tomonidan qaytariladigan qiymat odatda eâtiborga olinmaydi.
Yagona istisno â on<event> yordamida tayinlangan ishlov beruvchidan return false.
Barcha boshqa hollarda, return qiymati eâtiborga olinmaydi. Xususan, true qaytarishning maânosi yoâq.
Misol: menyu
Sayt menyusini koârib chiqing:
<ul id="menu" class="menu">
<li><a href="/html">HTML</a></li>
<li><a href="/javascript">JavaScript</a></li>
<li><a href="/css">CSS</a></li>
</ul>
CSS bilan qanday koârinishi:
Menyu elementlari <button> tugmalari emas, balki HTML havola <a> sifatida amalga oshirilgan. Buning bir necha sabablari bor:
- Koâp odamlar âoâng bosishâ â âyangi oynada ochishâ dan foydalanishni yoqtiradilar. Agar biz
<button>yoki<span>dan foydalansak, bu ishlamaydi. - Qidiruv tizimlari indekslash paytida
<a href="...">havolalarni kuzatadilar.
Shuning uchun biz markup-da <a> dan foydalanamiz. Lekin odatda biz JavaScript-da bosilishlarni qayta ishlamoqchimiz. Shuning uchun brauzerni standart harakatining oldini olishimiz kerak.
Mana shunday:
menu.onclick = function(event) {
if (event.target.nodeName != 'A') return;
let href = event.target.getAttribute('href');
alert( href ); // ...serverdan yuklash, UI yaratish va h.k.
return false; // brauzer harakatining oldini ol (URL ga o'tma)
};
Agar biz return false ni qoldirsak, kodimiz bajarilgandan soâng brauzer oâzini âstandart harakatiâ ni bajaradi â href dagi URL ga yoânaltiradi. Bu yerda bizga bu kerak emas, chunki biz bosishni oâzimiz qayta ishlamoqdamiz.
Aytgancha, bu yerda hodisa delegatsiyasidan foydalanish bizning menyumizni juda moslashuvchan qiladi. Biz ichki roâyxatlar qoâshishimiz va ularni CSS yordamida âpastga sirpanishâ uchun stillashtirshimiz mumkin.
Baâzi hodisalar bir-biriga oqib oâtadilar. Agar biz birinchi hodisaning oldini olsak, ikkinchisi boâlmaydi.
Masalan, <input> maydoni ustidagi mousedown unga fokuslanishga olib keladi va focus hodisasi yuz beradi. Agar biz mousedown hodisasining oldini olsak, fokus boâlmaydi.
Quyidagi birinchi <input> ga bosingchi â focus hodisasi sodir boâladi. Lekin ikkinchisiga bossangiz, fokus boâlmaydi.
<input value="Fokus ishlaydi" onfocus="this.value=''">
<input onmousedown="return false" onfocus="this.value=''" value="Menga bosing">
Buning sababi mousedown da brauzer harakati bekor qilingandir. Boshqa yoâl bilan kirish maydaniga kirish hali ham mumkin. Masalan, birinchi kirishdan ikkinchisiga oâtish uchun Tab tugmasi. Lekin sichqoncha bilan bosish endi mumkin emas.
âPassivâ ishlov beruvchi parametri
addEventListener ning ixtiyoriy passive: true parametri brauzerni ishlov beruvchi preventDefault() ni chaqirmasligini bildiradi.
Bu nima uchun kerak boâlishi mumkin?
Mobil qurilmalarda touchmove kabi baâzi hodisalar mavjud (foydalanuvchi barmogâini ekran boâylab siljitganda), ular sukut boâyicha scroll qilishga sabab boâladi, lekin bu scroll preventDefault() yordamida ishlov beruvchida oldini olish mumkin.
Shuning uchun brauzer bunday hodisani aniqlaganda, u avval barcha ishlov beruvchilarni qayta ishlashi kerak, soângra agar preventDefault hech qayerda chaqirilmagan boâlsa, u scroll bilan davom etishi mumkin. Bu UI da keraksiz kechikishlar va âtebranishlarâ ga sabab boâlishi mumkin.
passive: true parametri brauzerni ishlov beruvchi scroll ni bekor qilmasligini bildiradi. Keyin brauzer maksimal suyuq tajriba bilan darhol scroll qiladi va hodisa yoâl boâyicha qayta ishlanadi.
Baâzi brauzerlar uchun (Firefox, Chrome), touchstart va touchmove hodisalari uchun passive sukut boâyicha true dir.
event.defaultPrevented
event.defaultPrevented xossasi standart harakat oldini olingan boâlsa true, aks holda false boâladi.
Buning uchun qiziqarli foydalanish holati bor.
Bubbling va Capturing bobida biz event.stopPropagation() va nima uchun bubbling ni toâxtatish yomon ekanligi haqida gaplashgandik.
Baâzan biz event.defaultPrevented dan foydalanishimiz mumkin, boshqa hodisa ishlov beruvchilariga hodisa qayta ishlanganligini bildirish uchun.
Amaliy misolni koâraylik.
Sukut boâyicha brauzer contextmenu hodisasida (oâng sichqoncha bosish) standart variantlar bilan kontekst menyusini koârsatadi. Biz buning oldini olib, oâzimiznikini koârsatishimiz mumkin:
<button>O'ng bosish brauzer kontekst menyusini ko'rsatadi</button>
<button oncontextmenu="alert('Bizning menyumizni chizish'); return false">
O'ng bosish bizning kontekst menyumizni ko'rsatadi
</button>
Endi, kontekst menyudan tashqari, biz hujjat miqyosidagi kontekst menyusini amalga oshirishni istaymiz.
Oâng bosilganda, eng yaqin kontekst menyusi paydo boâlishi kerak.
<p>Hujjat kontekst menyusi uchun bu yerga o'ng bosing</p>
<button id="elem">Tugma kontekst menyusi uchun bu yerga o'ng bosing</button>
<script>
elem.oncontextmenu = function(event) {
event.preventDefault();
alert("Tugma kontekst menyusi");
};
document.oncontextmenu = function(event) {
event.preventDefault();
alert("Hujjat kontekst menyusi");
};
</script>
Muammo shundaki, elem ga bosganimizda, biz ikkita menyu olamiz: tugma darajasidagi va (hodisa yuqoriga koâtariladi) hujjat darajasidagi menyu.
Buni qanday tuzatish mumkin? Yechimlardan biri shunday oâylashdir: âTugma ishlov beruvchisida oâng bosishni qayta ishlasak, uning bubbling ni toâxtatingâ va event.stopPropagation() dan foydalaning:
<p>Hujjat menyusi uchun o'ng bosish</p>
<button id="elem">Tugma menyusi uchun o'ng bosish (event.stopPropagation bilan tuzatilgan)</button>
<script>
elem.oncontextmenu = function(event) {
event.preventDefault();
event.stopPropagation();
alert("Tugma kontekst menyusi");
};
document.oncontextmenu = function(event) {
event.preventDefault();
alert("Hujjat kontekst menyusi");
};
</script>
Endi tugma darajasidagi menyu moâljallangandek ishlaydi. Lekin narxi yuqori. Biz abadiy tashqi kodlar uchun oâng bosishlar haqidagi maâlumotlarga kirishni rad etamiz, shu jumladan statistikalarni yigâuvchi hisoblagichlar va boshqalar. Bu juda aqlsizlik.
Muqobil yechim document ishlov beruvchisida standart harakat oldini olinganligini tekshirish boâladi. Agar shunday boâlsa, demak hodisa qayta ishlangan va biz unga javob berishimiz shart emas.
<p>Hujjat menyusi uchun o'ng bosish (event.defaultPrevented uchun tekshiruv qo'shildi)</p>
<button id="elem">Tugma menyusi uchun o'ng bosish</button>
<script>
elem.oncontextmenu = function(event) {
event.preventDefault();
alert("Tugma kontekst menyusi");
};
document.oncontextmenu = function(event) {
if (event.defaultPrevented) return;
event.preventDefault();
alert("Hujjat kontekst menyusi");
};
</script>
Endi hammasi ham toâgâri ishlaydi. Agar bizda ichki elementlar boâlsa va har birining oâz kontekst menyusi boâlsa, bu ham ishlaydi. Har bir contextmenu ishlov beruvchisida event.defaultPrevented ni tekshirishni unutmang.
Koârib turganimizdek, event.stopPropagation() va event.preventDefault() (return false sifatida ham tanilgan) ikki xil narsa. Ular bir-birlari bilan bogâliq emas.
Ichki kontekst menyularini amalga oshirishning boshqa usullari ham mavjud. Ulardan biri document.oncontextmenu uchun ishlov beruvchi va boshqa ishlov beruvchilarni saqlashga imkon beruvchi metodlarga ega yagona global obyektga ega boâlish.
Obyekt har qanday oâng bosishni ushlaydi, saqlangan ishlov beruvchilarni koârib chiqadi va tegishli birini ishga tushiradi.
Lekin keyin kontekst menyusini xohlaydigan har bir kod qismi ushbu obyekt haqida bilishi va oâz contextmenu ishlov beruvchisi oârniga uning yordamidan foydalanishi kerak.
Xulosa
Koâplab standart brauzer harakatlari mavjud:
mousedownâ tanlovni boshlaydi (tanlash uchun sichqonchani siljiting).<input type="checkbox">daclickâinputni belgilaydi/belgilamaydi.submitâ<input type="submit">ga bosish yoki forma maydonida Enter bosish ushbu hodisani sodir qiladi va brauzer undan soâng formani yuboradi.keydownâ tugmani bosish maydonga belgi qoâshish yoki boshqa harakatlarga olib kelishi mumkin.contextmenuâ hodisa oâng bosishda sodir boâladi, harakat brauzer kontekst menyusini koârsatishdir.- â¦va boshqalarâ¦
Agar biz hodisani faqat JavaScript orqali qayta ishlamoqchi boâlsak, barcha standart harakatlarning oldini olish mumkin.
Standart harakatning oldini olish uchun â event.preventDefault() yoki return false dan foydalaning. Ikkinchi usul faqat on<event> bilan tayinlangan ishlov beruvchilar uchun ishlaydi.
addEventListener ning passive: true parametri brauzerni harakatning oldini olinmasligini bildiradi. Bu touchstart va touchmove kabi baâzi mobil hodisalar uchun foydali, brauzerni scroll qilishdan oldin barcha ishlov beruvchilar tugashini kutmasligi kerakligini bildiradi.
Agar standart harakatning oldini olingan boâlsa, event.defaultPrevented qiymati true boâladi, aks holda false.
Texnik jihatdan, standart harakatlarning oldini olib, JavaScript qoâshish orqali biz har qanday elementlarning xatti-harakatlarini sozlashimiz mumkin. Masalan, biz havola <a> ni tugma kabi ishlatishimiz va tugma <button> ni havola kabi ishlashimiz mumkin (boshqa URL ga yoânaltirish yoki boshqa).
Lekin biz umuman HTML elementlarining semantik maânosini saqlab qolishimiz kerak. Masalan, <a> tugma emas, navigatsiya bajarishi kerak.
âFaqat yaxshi narsaâ boâlishdan tashqari, bu sizni HTML ni dostuplik nuqtai nazaridan yaxshiroq qiladi.
Shuningdek, agar biz <a> misolini koârsak, shuni yodda tutingki: brauzer bizga bunday havolalarni yangi oynada ochishga imkon beradi (ularni oâng bosish va boshqa usullar orqali). Va odamlar buni yoqtiradilar. Lekin agar biz JavaScript yordamida tugmani havola kabi ishlashimiz va hattoki CSS yordamida havolaga oâxshatishimiz, <a> ga xos brauzer funksiyalari hali ham u uchun ishlamaydi.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepenâ¦)