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

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

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

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

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

सभी मॉडर्न ब्राउज़र इवेंट कैप्चर करने की सुविधा देते हैं, लेकिन डेवलपर इसका इस्तेमाल बहुत कम करते हैं. दिलचस्प बात यह है कि इवेंट करने का सिर्फ़ यही एक तरीका था, जिसका Netscape मूल रूप से समर्थन करता था. 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,
);

कंसोल का आउटपुट इस बात पर निर्भर करेगा कि आपने किस एलिमेंट पर क्लिक किया है. डीओएम ट्री (#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 पर टॉम विल्सन की हीरो इमेज.