JavaScript इवेंट के बारे में ज़्यादा जानकारी

preventDefault और stopPropagation: किस तरीके का इस्तेमाल कब करना है और हर तरीका क्या करता है.

JavaScript इवेंट को हैंडल करना अक्सर आसान होता है. यह बात खास तौर पर तब ज़्यादा सही होती है, जब किसी आसान (अपेक्षाकृत फ़्लैट) एचटीएमएल स्ट्रक्चर का इस्तेमाल किया जा रहा हो. हालांकि, जब इवेंट एलिमेंट की हैरारकी के ज़रिए ट्रैवल कर रहे हैं या प्रॉपेगेट कर रहे हैं, तो चीज़ें थोड़ी मुश्किल हो जाती हैं. आम तौर पर, ऐसा तब होता है, जब डेवलपर अपनी समस्याओं को हल करने के लिए, stopPropagation() और/या preventDefault() से संपर्क करते हैं. अगर आपने कभी यह सोचा है कि "मैं preventDefault() आज़माऊंगा और अगर वह काम नहीं करता है, तो stopPropagation() आज़माऊंगा. अगर वह भी काम नहीं करता है, तो दोनों आज़माऊंगा", तो यह लेख आपके लिए है! हम आपको बताएंगे कि हर तरीका क्या करता है और किसका इस्तेमाल कब करना चाहिए. साथ ही, आपको कई काम के उदाहरण भी देंगे. मेरा लक्ष्य है कि आपकी उलझन को हमेशा के लिए खत्म कर दिया जाए.

हालांकि, ज़्यादा जानकारी देने से पहले, यह जानना ज़रूरी है कि JavaScript में इवेंट मैनेज करने के दो तरीके हैं. ये तरीके सभी आधुनिक ब्राउज़र में काम करते हैं. हालांकि, Internet Explorer 9 से पहले के वर्शन में इवेंट कैप्चर करने की सुविधा काम नहीं करती थी.

इवेंटिंग स्टाइल (कैप्चर करना और बबल करना)

सभी आधुनिक ब्राउज़र, इवेंट कैप्चर करने की सुविधा के साथ काम करते हैं. हालांकि, डेवलपर इसका इस्तेमाल बहुत कम करते हैं. दिलचस्प बात यह है कि नेटस्केप में मूल रूप से सिर्फ़ इवेंट ट्रिगर करने का यह तरीका काम करता था. Netscape का सबसे बड़ा प्रतिद्वंद्वी, Microsoft Internet Explorer, इवेंट कैप्चर करने की सुविधा का इस्तेमाल नहीं करता था. इसके बजाय, यह इवेंट बबलिंग नाम के इवेंट के दूसरे स्टाइल का इस्तेमाल करता था. W3C के गठन के बाद, उन्हें इवेंट ट्रिगर करने के दोनों तरीकों में फ़ायदे मिले. इसलिए, उन्होंने यह एलान किया कि ब्राउज़र को addEventListener तरीके के तीसरे पैरामीटर की मदद से, दोनों तरीकों के साथ काम करना चाहिए. मूल रूप से, वह पैरामीटर सिर्फ़ एक बूलियन था. हालांकि, सभी आधुनिक ब्राउज़र में तीसरे पैरामीटर के तौर पर options ऑब्जेक्ट का इस्तेमाल किया जा सकता है. इसका इस्तेमाल, इवेंट कैप्चर करने की सुविधा का इस्तेमाल करना है या नहीं, यह तय करने के लिए किया जा सकता है:

someElement.addEventListener('click', myClickHandler, { capture: true | false });

ध्यान दें कि options ऑब्जेक्ट और उसकी capture प्रॉपर्टी, दोनों को शामिल करना ज़रूरी नहीं है. अगर इनमें से किसी एक को छोड़ा जाता है, तो capture की डिफ़ॉल्ट वैल्यू false होती है. इसका मतलब है कि इवेंट बबल करने की सुविधा का इस्तेमाल किया जाएगा.

इवेंट कैप्चर करना

अगर आपका इवेंट हैंडलर "कैप्चर करने के फ़ेज़ में सुन रहा है", तो इसका क्या मतलब है? इसे समझने के लिए, हमें यह जानना होगा कि इवेंट कैसे शुरू होते हैं और कैसे ट्रैवल करते हैं. यह बात सभी इवेंट के लिए सही है. भले ही, डेवलपर के तौर पर आप इसका इस्तेमाल न करें, इसकी परवाह न करें या इस बारे में न सोचें.

सभी इवेंट, विंडो से शुरू होते हैं और पहले कैप्चर करने के चरण से गुज़रते हैं. इसका मतलब है कि जब कोई इवेंट डिस्पैच किया जाता है, तो वह विंडो शुरू करता है और अपने टारगेट एलिमेंट की ओर "नीचे की ओर" सबसे पहले जाता है. ऐसा तब भी होता है, जब आप सिर्फ़ बुलबलिंग फ़ेज़ में सुन रहे हों. मार्कअप और JavaScript के लिए, यहां दिए गए उदाहरण देखें:

<html>
 
<body>
   
<div id="A">
     
<div id="B">
       
<div id="C"></div>
     
</div>
   
</div>
 
</body>
</html>
document.getElementById('C').addEventListener(
 
'click',
 
function (e) {
    console
.log('#C was clicked');
 
},
 
true,
);

जब कोई उपयोगकर्ता एलिमेंट #C पर क्लिक करता है, तो window से शुरू होने वाला इवेंट डिस्पैच हो जाता है. इसके बाद, यह इवेंट अपने वंशजों के ज़रिए इस तरह से प्रसारित होगा:

window => document => <html> => <body> => और इसी तरह, जब तक टारगेट पूरा नहीं हो जाता.

इससे कोई फ़र्क़ नहीं पड़ता कि window या document या <html> एलिमेंट या <body> एलिमेंट (या अपने टारगेट के रास्ते पर मौजूद किसी भी अन्य एलिमेंट) पर क्लिक इवेंट के लिए कोई भी सुनवाई नहीं की जा रही है. इवेंट अब भी window बजे शुरू होता है और ऊपर बताए गए तरीके से अपनी प्रोसेस शुरू करता है.

हमारे उदाहरण में, क्लिक इवेंट window से अपने टारगेट एलिमेंट (इस मामले में, #C) तक प्रोपगेट (यह एक अहम शब्द है, क्योंकि यह सीधे तौर पर stopPropagation() तरीके के काम करने के तरीके से जुड़ा होगा और इस दस्तावेज़ में बाद में इसकी जानकारी दी जाएगी) करेगा. इसके लिए, यह window और #C के बीच मौजूद हर एलिमेंट से गुज़रेगा.

इसका मतलब है कि क्लिक इवेंट window पर शुरू होगा और ब्राउज़र ये सवाल पूछेगा:

"क्या कैप्चर करने के फ़ेज़ में, window पर क्लिक इवेंट के लिए कोई भी ट्रिगर सुन रहा है?" अगर ऐसा है, तो सही इवेंट हैंडलर ट्रिगर होंगे. हमारे उदाहरण में, कोई भी एलिमेंट नहीं है. इसलिए, कोई भी हैंडलर ट्रिगर नहीं होगा.

इसके बाद, इवेंट document पर प्रोपगेट हो जाएगा और ब्राउज़र पूछेगा: "क्या कैप्चर करने के फ़ेज़ में, document पर क्लिक इवेंट के लिए कोई भी सुन रहा है?" ऐसा होने पर, सही इवेंट हैंडलर ट्रिगर होंगे.

इसके बाद, इवेंट <html> एलिमेंट पर प्रोपगेट हो जाएगा और ब्राउज़र पूछेगा: "क्या कैप्चर करने के फ़ेज़ में, <html> एलिमेंट पर क्लिक के लिए कोई भी प्रोसेस चल रही है?" अगर ऐसा होता है, तो सही इवेंट मैनेजर ट्रिगर हो जाएंगे.

इसके बाद, इवेंट <body> एलिमेंट पर प्रोपगेट हो जाएगा और ब्राउज़र पूछेगा: "क्या कैप्चर करने के फ़ेज़ में, <body> एलिमेंट पर क्लिक इवेंट के लिए कोई भी प्रोसेस चल रही है?" अगर ऐसा होता है, तो सही इवेंट हैंडलर ट्रिगर हो जाएंगे.

इसके बाद, इवेंट #A एलिमेंट में प्रोपगेट हो जाएगा. फिर से, ब्राउज़र पूछेगा: "क्या कैप्चर करने के फ़ेज़ में, #A पर क्लिक इवेंट के लिए कोई भी सुन रहा है और अगर ऐसा है, तो सही इवेंट हैंडलर ट्रिगर होंगे.

इसके बाद, इवेंट #B एलिमेंट में प्रोपगेट हो जाएगा और वही सवाल पूछा जाएगा.

आखिर में, इवेंट अपने टारगेट तक पहुंच जाएगा और ब्राउज़र पूछेगा: "क्या कैप्चर करने के फ़ेज़ में, #C एलिमेंट पर क्लिक इवेंट के लिए कोई भी सुन रहा है?" इस बार जवाब है, "हां!" जब इवेंट टारगेट पर होता है, तब उस छोटी अवधि को "टारगेट फ़ेज़" कहा जाता है. इस समय, इवेंट हैंडलर ट्रिगर हो जाएगा. ब्राउज़र, console.log "#C पर क्लिक किया गया" दिखाएगा. इसके बाद, हमारा काम पूरा हो जाएगा, है न? गलत है! हमने अभी तक बहुत कुछ नहीं किया है. यह प्रोसेस जारी रहती है, लेकिन अब यह बबलिंग फ़ेज़ में बदल जाती है.

इवेंट बबल

ब्राउज़र आपसे पूछेगा:

"क्या बबलिंग फ़ेज़ में, #C पर क्लिक इवेंट के लिए कोई भी सुन रहा है?" यहां ध्यान से देखें. क्लिक (या किसी भी तरह के इवेंट) को कैप्चर करने और बबल करने के दोनों चरणों में देखा जा सकता है. अगर आपने दोनों चरणों में इवेंट हैंडलर को जोड़ा है, तो हां, दोनों इवेंट हैंडलर एक ही एलिमेंट के लिए ट्रिगर होंगे. उदाहरण के लिए, .addEventListener() को दो बार कॉल करके, एक बार capture = true और एक बार capture = false के साथ. हालांकि, यह भी ध्यान रखना ज़रूरी है कि ये अलग-अलग चरणों में ट्रिगर होते हैं. पहला चरण, डेटा कैप्चर करने का चरण होता है और दूसरा चरण, डेटा बबल करने का चरण होता है.

इसके बाद, इवेंट अपने पैरंट एलिमेंट #B पर प्रोपगेट (आम तौर पर इसे "बबल" कहा जाता है, क्योंकि ऐसा लगता है कि इवेंट, DOM ट्री में "अप" की ओर जा रहा है) होगा और ब्राउज़र पूछेगा: "क्या बबल करने के दौरान, #B पर क्लिक इवेंट को कोई सुन रहा है?" हमारे उदाहरण में, कुछ भी नहीं है, इसलिए कोई भी हैंडलर ट्रिगर नहीं होगा.

इसके बाद, इवेंट #A पर बबल हो जाएगा और ब्राउज़र पूछेगा: "क्या बबल होने के दौरान, #A पर क्लिक इवेंट को कोई सुन रहा है?"

इसके बाद, इवेंट <body> पर बबल होगा: "क्या बबल करने के फ़ेज़ में, <body> एलिमेंट पर क्लिक इवेंट सुनने वाला कोई भी एलिमेंट है?"

इसके बाद, <html> एलिमेंट: "क्या बबल करने के फ़ेज़ में, <html> एलिमेंट पर क्लिक इवेंट के लिए कोई भी सुन रहा है?

इसके बाद, document: "क्या बबल अप करने वाले फ़ेज़ में, document पर क्लिक इवेंट को कोई सुन रहा है?"

आखिर में, window: "क्या बबल करने के दौरान, विंडो पर क्लिक इवेंट को कोई भी सुन रहा है?"

वाह! यह एक लंबी प्रक्रिया है और हो सकता है कि अब तक हमारा इवेंट बहुत थक गया हो. हालांकि, भरोसेमंद या नहीं, यह हर इवेंट के लिए एक सामान्य प्रक्रिया है! ज़्यादातर समय, इस पर कभी ध्यान नहीं दिया जाता, क्योंकि आम तौर पर डेवलपर को सिर्फ़ एक या दूसरे इवेंट फ़ेज़ में दिलचस्पी होती है. आम तौर पर, यह दिलचस्पी बबलिंग फ़ेज़ में होती है.

इवेंट कैप्चर करने और इवेंट बबल करने के साथ-साथ, हैंडलर ट्रिगर होने पर कंसोल में कुछ नोट लॉग करने में कुछ समय बिताना अच्छा होता है. किसी इवेंट के पाथ को देखना बहुत अहम होता है. यहां एक ऐसा उदाहरण दिया गया है जो दोनों चरणों में हर एलिमेंट को सुनता है.

<html>
 
<body>
   
<div id="A">
     
<div id="B">
       
<div id="C"></div>
     
</div>
   
</div>
 
</body>
</html>
document.addEventListener(
 
'click',
 
function (e) {
    console
.log('click on document in capturing phase');
 
},
 
true,
);
// document.documentElement == <html>
document
.documentElement.addEventListener(
 
'click',
 
function (e) {
    console
.log('click on <html> in capturing phase');
 
},
 
true,
);
document
.body.addEventListener(
 
'click',
 
function (e) {
    console
.log('click on <body> in capturing phase');
 
},
 
true,
);
document
.getElementById('A').addEventListener(
 
'click',
 
function (e) {
    console
.log('click on #A in capturing phase');
 
},
 
true,
);
document
.getElementById('B').addEventListener(
 
'click',
 
function (e) {
    console
.log('click on #B in capturing phase');
 
},
 
true,
);
document
.getElementById('C').addEventListener(
 
'click',
 
function (e) {
    console
.log('click on #C in capturing phase');
 
},
 
true,
);

document
.addEventListener(
 
'click',
 
function (e) {
    console
.log('click on document in bubbling phase');
 
},
 
false,
);
// document.documentElement == <html>
document
.documentElement.addEventListener(
 
'click',
 
function (e) {
    console
.log('click on <html> in bubbling phase');
 
},
 
false,
);
document
.body.addEventListener(
 
'click',
 
function (e) {
    console
.log('click on <body> in bubbling phase');
 
},
 
false,
);
document
.getElementById('A').addEventListener(
 
'click',
 
function (e) {
    console
.log('click on #A in bubbling phase');
 
},
 
false,
);
document
.getElementById('B').addEventListener(
 
'click',
 
function (e) {
    console
.log('click on #B in bubbling phase');
 
},
 
false,
);
document
.getElementById('C').addEventListener(
 
'click',
 
function (e) {
    console
.log('click on #C in bubbling phase');
 
},
 
false,
);

कंसोल का आउटपुट इस बात पर निर्भर करेगा कि आपने किस एलिमेंट पर क्लिक किया है. अगर आपने DOM ट्री में "सबसे अंदर" मौजूद एलिमेंट (#C एलिमेंट) पर क्लिक किया, तो आपको इनमें से हर इवेंट हैंडलर ट्रिगर होते हुए दिखेंगे. सीएसएस स्टाइल की मदद से, यह साफ़ तौर पर पता चलता है कि कौनसा एलिमेंट कौनसा है. यहां कंसोल के #C एलिमेंट का स्क्रीनशॉट दिया गया है:

"click on document in capturing phase"
"click on <html> in capturing phase"
"click on <body> in capturing phase"
"click on #A in capturing phase"
"click on #B in capturing phase"
"click on #C in capturing phase"
"click on #C in bubbling phase"
"click on #B in bubbling phase"
"click on #A in bubbling phase"
"click on <body> in bubbling phase"
"click on <html> in bubbling phase"
"click on document in bubbling phase"

नीचे दिए गए लाइव डेमो में, इस सुविधा को इंटरैक्टिव तरीके से आज़माया जा सकता है. #C एलिमेंट पर क्लिक करें और कंसोल आउटपुट देखें.

event.stopPropagation()

अब हम event.stopPropagation() पर ध्यान दे सकते हैं. इससे हमें यह समझने में मदद मिलेगी कि इवेंट कहां से शुरू होते हैं और कैप्चर करने के चरण और बबल करने के चरण, दोनों में वे डीओएम के ज़रिए कैसे चलते हैं (यानी प्रॉपेगेट होते हैं).

stopPropagation() तरीके को ज़्यादातर नेटिव DOM इवेंट पर कॉल किया जा सकता है. हम "ज़्यादातर" इसलिए कहते हैं, क्योंकि कुछ ऐसे भी हैं जिन पर इस तरीके को कॉल करने से कुछ नहीं होगा (क्योंकि इवेंट शुरू होने के साथ ही प्रोपेगेट नहीं होता). focus, blur, load, scroll जैसे इवेंट और कुछ अन्य इवेंट इस कैटगरी में आते हैं. stopPropagation() को कॉल किया जा सकता है, लेकिन कुछ दिलचस्प नहीं होगा, क्योंकि ये इवेंट प्रोपेगेट नहीं होते.

लेकिन stopPropagation क्या करता है?

यह वही काम करता है जो इसके नाम से पता चलता है. इसे कॉल करने के बाद, इवेंट उस बिंदु से, उन सभी एलिमेंट में प्रसार करना बंद कर देगा जिनमें यह अन्यथा ट्रैवल करता. यह दोनों निर्देशों (कैप्चर करने और बबल करने) के लिए सही है. इसलिए, अगर कैप्चर करने के फ़ेज़ में कहीं भी stopPropagation() को कॉल किया जाता है, तो इवेंट कभी भी टारगेट फ़ेज़ या बबल करने वाले फ़ेज़ तक नहीं पहुंच पाएगा. अगर इसे बबल अप करने के चरण में कॉल किया जाता है, तो यह पहले ही कैप्चर करने के चरण से गुज़र चुका होगा. हालांकि, इसे कॉल करने के बाद, यह "बबल अप" करना बंद कर देगा.

हमारे उसी उदाहरण वाले मार्कअप पर वापस आकर, आपको क्या लगता है कि अगर हमने #B एलिमेंट पर कैप्चर करने के फ़ेज़ में stopPropagation() को कॉल किया, तो क्या होगा?

इससे यह आउटपुट मिलेगा:

"click on document in capturing phase"
"click on <html> in capturing phase"
"click on <body> in capturing phase"
"click on #A in capturing phase"
"click on #B in capturing phase"

नीचे दिए गए लाइव डेमो में, इस सुविधा को इंटरैक्टिव तरीके से आज़माया जा सकता है. लाइव डेमो में #C एलिमेंट पर क्लिक करें और कंसोल आउटपुट देखें.

बबलिंग फ़ेज़ में, #A पर प्रॉपेगेशन को कैसे रोकें? इससे यह आउटपुट मिलेगा:

"click on document in capturing phase"
"click on <html> in capturing phase"
"click on <body> in capturing phase"
"click on #A in capturing phase"
"click on #B in capturing phase"
"click on #C in capturing phase"
"click on #C in bubbling phase"
"click on #B in bubbling phase"
"click on #A in bubbling phase"

नीचे दिए गए लाइव डेमो में, इस सुविधा को इंटरैक्टिव तरीके से आज़माया जा सकता है. लाइव डेमो में #C एलिमेंट पर क्लिक करें और कंसोल आउटपुट देखें.

एक और, सिर्फ़ मज़े के लिए. अगर हम #C के लिए टारगेट फ़ेज़ में stopPropagation() को कॉल करते हैं, तो क्या होगा? याद रखें कि "टारगेट फ़ेज़", उस समयावधि को कहा जाता है जब इवेंट अपने टारगेट पर होता है. इससे यह आउटपुट मिलेगा:

"click on document in capturing phase"
"click on <html> in capturing phase"
"click on <body> in capturing phase"
"click on #A in capturing phase"
"click on #B in capturing phase"
"click on #C in capturing phase"

ध्यान दें कि #C के लिए इवेंट हैंडलर, "कैप्चर करने के चरण में #C पर क्लिक करें" को लॉग करने के बाद भी चलता रहा, लेकिन "बबल करने के चरण में #C पर क्लिक करें" को लॉग करने के बाद नहीं. यह पूरी तरह से सही है. हमने stopPropagation() को पहले से कॉल किया है, इसलिए यह वह पॉइंट है जहां इवेंट का प्रॉपेगेशन बंद हो जाएगा.

नीचे दिए गए लाइव डेमो में, इस सुविधा को इंटरैक्टिव तरीके से आज़माया जा सकता है. लाइव डेमो में #C एलिमेंट पर क्लिक करें और कंसोल आउटपुट देखें.

इनमें से किसी भी लाइव डेमो में, हम आपको एक्सपेरिमेंट करने का सुझाव देते हैं. सिर्फ़ #A एलिमेंट या सिर्फ़ body एलिमेंट पर क्लिक करके देखें. यह अनुमान लगाने की कोशिश करें कि क्या होगा और फिर देखें कि आपका अनुमान सही है या नहीं. इस बिंदु पर, आपको काफ़ी सटीक अनुमान लगाने में मदद मिल सकती है.

event.stopImmediatePropagation()

यह तरीका कितना अजीब और कम इस्तेमाल किया जाने वाला है? यह stopPropagation से मिलता-जुलता है. हालांकि, किसी इवेंट को उसके वंशजों (कैप्चर करने) या पूर्वजों (बबल करने) तक जाने से रोकने के बजाय, यह तरीका सिर्फ़ तब लागू होता है, जब आपके पास एक से ज़्यादा इवेंट हैं. addEventListener(), इवेंट के मल्टीकास्ट स्टाइल के साथ काम करता है. इसलिए, किसी एक एलिमेंट में इवेंट हैंडलर को एक से ज़्यादा बार जोड़ा जा सकता है. ऐसा होने पर, ज़्यादातर ब्राउज़र में इवेंट हैंडलर उसी क्रम में लागू होते हैं जिस क्रम में उन्हें जोड़ा गया था. stopImmediatePropagation() को कॉल करने से, बाद में होने वाली किसी भी प्रोसेस को ट्रिगर होने से रोका जा सकता है. नीचे दिया गया उदाहरण देखें:

<html>
 
<body>
   
<div id="A">I am the #A element</div>
 
</body>
</html>
document.getElementById('A').addEventListener(
 
'click',
 
function (e) {
    console
.log('When #A is clicked, I shall run first!');
 
},
 
false,
);

document
.getElementById('A').addEventListener(
 
'click',
 
function (e) {
    console
.log('When #A is clicked, I shall run second!');
    e
.stopImmediatePropagation();
 
},
 
false,
);

document
.getElementById('A').addEventListener(
 
'click',
 
function (e) {
    console
.log('When #A is clicked, I would have run third, if not for stopImmediatePropagation');
 
},
 
false,
);

ऊपर दिए गए उदाहरण से, कंसोल में यह आउटपुट दिखेगा:

"When #A is clicked, I shall run first!"
"When #A is clicked, I shall run second!"

ध्यान दें कि तीसरा इवेंट हैंडलर कभी नहीं चलता, क्योंकि दूसरा इवेंट हैंडलर e.stopImmediatePropagation() को कॉल करता है. अगर हमने e.stopPropagation() को कॉल किया होता, तो तीसरा हैंडलर अब भी चलता रहता.

event.preventDefault()

अगर stopPropagation() किसी इवेंट को "नीचे" (कैप्चर करने) या "ऊपर" (बबल करने) जाने से रोकता है, तो preventDefault() क्या करता है? ऐसा लगता है कि यह भी कुछ ऐसा ही करता है. क्या ऐसा है?

दरअसल ऐसा नहीं है. इन दोनों को अक्सर एक ही समझा जाता है, लेकिन असल में इनका एक-दूसरे से कोई लेना-देना नहीं है. preventDefault() दिखने पर, अपने मन में "कार्रवाई" शब्द जोड़ें. "डिफ़ॉल्ट कार्रवाई को रोकें" के बारे में सोचें.

साथ ही, डिफ़ॉल्ट रूप से कौनसी कार्रवाई की जा सकती है? माफ़ करें, इसका जवाब साफ़ तौर पर नहीं दिया जा सकता, क्योंकि यह सवाल में दिए गए एलिमेंट + इवेंट कॉम्बिनेशन पर काफ़ी निर्भर करता है. और मामले को और भी उलझाने के लिए, कभी-कभी कोई डिफ़ॉल्ट कार्रवाई भी नहीं होती!

चलिए, इसे समझने के लिए एक बहुत ही आसान उदाहरण से शुरू करते हैं. किसी वेब पेज पर मौजूद लिंक पर क्लिक करने पर, आपको क्या दिखने की उम्मीद है? यह ज़रूरी है कि ब्राउज़र, उस लिंक से दिए गए यूआरएल पर ले जाए. इस मामले में, एलिमेंट एक ऐंकर टैग है और इवेंट एक क्लिक इवेंट है. इस कॉम्बिनेशन (<a> + click) की "डिफ़ॉल्ट कार्रवाई", लिंक के href पर नेविगेट करना है. अगर आपको ब्राउज़र को उस डिफ़ॉल्ट कार्रवाई को करने से रोकना है, तो क्या करें? इसका मतलब है कि मान लें कि आपको ब्राउज़र को <a> एलिमेंट के href एट्रिब्यूट से तय किए गए यूआरएल पर जाने से रोकना है, तो क्या करें? preventDefault() आपके लिए यह काम करेगा. इस उदाहरण पर ध्यान दें:

<a id="avett" href="https://www.theavettbrothers.com/welcome">The Avett Brothers</a>
document.getElementById('avett').addEventListener(
 
'click',
 
function (e) {
    e
.preventDefault();
    console
.log('Maybe we should just play some of their music right here instead?');
 
},
 
false,
);

नीचे दिए गए लाइव डेमो में, इस सुविधा को इंटरैक्टिव तरीके से आज़माया जा सकता है. The Avett Brothers लिंक पर क्लिक करें और कंसोल के आउटपुट को देखें. साथ ही, यह भी देखें कि आपको Avett Brothers की वेबसाइट पर रीडायरेक्ट नहीं किया गया है.

आम तौर पर, The Avett Brothers के लेबल वाले लिंक पर क्लिक करने से, www.theavettbrothers.com पर ब्राउज़ किया जा सकता है. हालांकि, इस मामले में हमने <a> एलिमेंट में क्लिक इवेंट हैंडलर को जोड़ा है और यह बताया है कि डिफ़ॉल्ट कार्रवाई को रोका जाना चाहिए. इसलिए, जब कोई उपयोगकर्ता इस लिंक पर क्लिक करता है, तो उसे कहीं भी नहीं भेजा जाएगा. इसके बजाय, कंसोल सिर्फ़ "क्या हमें इसके बजाय, सीधे यहां उसका कुछ संगीत चलाना चाहिए?" को लॉग करेगा.

डिफ़ॉल्ट कार्रवाई को रोकने के लिए, कौनसे अन्य एलिमेंट/इवेंट कॉम्बिनेशन का इस्तेमाल किया जा सकता है? मैं सभी विकल्पों की सूची नहीं बना सकता. कभी-कभी आपको एक्सपेरिमेंट करके देखना होगा. हालांकि, यहां कुछ उदाहरण दिए गए हैं:

  • <form> एलिमेंट + "सबमिट" इवेंट: preventDefault() इस कॉम्बिनेशन से फ़ॉर्म सबमिट होने से रोका जा सकता है. अगर आपको पुष्टि करनी है और कोई चीज़ गलत हो जाती है, तो फ़ॉर्म को सबमिट होने से रोकने के लिए, preventDefault को कॉल किया जा सकता है.

  • <a> एलिमेंट + "क्लिक" इवेंट: preventDefault() इस कॉम्बिनेशन के लिए, ब्राउज़र को <a> एलिमेंट के href एट्रिब्यूट में बताए गए यूआरएल पर नेविगेट करने से रोका जाता है.

  • document + "mousewheel" इवेंट: preventDefault() इस कॉम्बिनेशन के लिए, माउसव्हील की मदद से पेज को स्क्रोल करने से रोका जाता है. हालांकि, कीबोर्ड की मदद से स्क्रोल करने की सुविधा काम करती रहेगी.
    ↜ इसके लिए, { passive: false } के साथ addEventListener() को कॉल करना ज़रूरी है.

  • document + "keydown" इवेंट: preventDefault() इस कॉम्बिनेशन के लिए घातक है. इससे पेज का इस्तेमाल करना मुश्किल हो जाता है. साथ ही, कीबोर्ड से स्क्रोल करने, टैब करने, और कीबोर्ड से हाइलाइट करने की सुविधा भी काम नहीं करती.

  • document + "mousedown" इवेंट: इस कॉम्बिनेशन के लिए preventDefault(), माउस से टेक्स्ट को हाइलाइट करने और माउस को दबाकर की जाने वाली किसी भी "डिफ़ॉल्ट" कार्रवाई को रोक देगा.

  • <input> एलिमेंट + "keypress" इवेंट: इस कॉम्बिनेशन के लिए preventDefault(), उपयोगकर्ता के टाइप किए गए वर्णों को इनपुट एलिमेंट तक पहुंचने से रोक देगा. हालांकि, ऐसा न करें. ऐसा करने की कोई मान्य वजह नहीं है.

  • document + "contextmenu" इवेंट: preventDefault() इस कॉम्बिनेशन के लिए, जब कोई उपयोगकर्ता राइट क्लिक करता है या लंबे समय तक दबाता है (या किसी भी ऐसे दूसरे तरीके से कॉन्टेक्स्ट मेन्यू दिखाता है), तो नेटिव ब्राउज़र कॉन्टेक्स्ट मेन्यू को दिखने से रोकता है.

यह पूरी सूची नहीं है. हालांकि, हमें उम्मीद है कि इससे आपको यह पता चल गया होगा कि preventDefault() का इस्तेमाल कैसे किया जा सकता है.

कोई मज़ेदार प्रैंक?

दस्तावेज़ से शुरू करके, कैप्चर करने के दौरान stopPropagation() और preventDefault() करने पर क्या होगा? हंसी-मज़ाक़ शुरू हो जाता है! नीचे दिया गया कोड स्निपेट, किसी भी वेब पेज को पूरी तरह से काम का नहीं बना पाएगा:

function preventEverything(e) {
  e
.preventDefault();
  e
.stopPropagation();
  e
.stopImmediatePropagation();
}

document
.addEventListener('click', preventEverything, true);
document
.addEventListener('keydown', preventEverything, true);
document
.addEventListener('mousedown', preventEverything, true);
document
.addEventListener('contextmenu', preventEverything, true);
document
.addEventListener('mousewheel', preventEverything, { capture: true, passive: false });

हमें नहीं पता कि आपको ऐसा क्यों करना है. ऐसा शायद किसी को गुमराह करने के लिए किया जा सकता है. हालांकि, यह जानना ज़रूरी है कि ऐसा क्यों होता है और इससे क्या समस्याएं आती हैं.

सभी इवेंट window से शुरू होते हैं. इसलिए, इस स्निपेट में हम click, keydown, mousedown, contextmenu, और mousewheel इवेंट को उन सभी एलिमेंट से रोक रहे हैं जो शायद उन्हें सुन रहे हों. हम stopImmediatePropagation को भी कॉल करते हैं, ताकि इस फ़ंक्शन के बाद दस्तावेज़ से जुड़े सभी हैंडलर को भी रोका जा सके.

ध्यान दें कि stopPropagation() और stopImmediatePropagation(), पेज को काम का नहीं बनाते. ये सिर्फ़ इवेंट को उस जगह से रोकते हैं जहां वे जाने वाले होते हैं.

हालांकि, हम preventDefault() को भी कॉल करते हैं. आपको याद होगा कि यह डिफ़ॉल्ट कार्रवाई को रोकता है. इसलिए, कोई भी डिफ़ॉल्ट कार्रवाई नहीं की जा सकती. जैसे, माउसव्हील स्क्रोल, कीबोर्ड स्क्रोल या हाइलाइट या टैब करना, लिंक पर क्लिक करना, कॉन्टेक्स्ट मेन्यू दिखाना वगैरह. इस वजह से, पेज का इस्तेमाल नहीं किया जा सकता.

लाइव डेमो

इस लेख में दिए गए सभी उदाहरणों को एक ही जगह पर देखने के लिए, यहां एम्बेड किया गया डेमो देखें.

आभार

Unsplash पर टॉम विल्सन की हीरो इमेज.