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

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

स्टीफ़न चूर
स्टीफ़न स्टर

Event.stopPropagation() और Event.preventDefault()

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

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

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

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

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

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

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

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

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

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

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

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

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

इवेंट बबलिंग

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

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

इसके बाद, इवेंट अपने पैरंट एलिमेंट #B पर प्रमोशन (आम तौर पर, इसे "बबल" के तौर पर कहा जाता है, क्योंकि ऐसा लगता है कि इवेंट, डीओएम ट्री में "ऊपर" की यात्रा कर रहा है) होगा. इसके बाद, ब्राउज़र यह पूछेगा: "क्या #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()

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

(ज़्यादातर) नेटिव DOM इवेंट पर stopPropagation() तरीके को कॉल किया जा सकता है. मैं "ज़्यादातर" कहता हूं, क्योंकि कुछ ऐसे हैं जिन पर इस तरीके को कॉल करने से कुछ नहीं होगा (क्योंकि इवेंट शुरू होने के लिए सही नहीं होता). 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 + "माउसव्हील" इवेंट: इस कॉम्बिनेशन के लिए preventDefault(), माउसव्हील से पेज स्क्रोल करने से रोकता है (हालांकि, कीबोर्ड से स्क्रोल करना अब भी काम करेगा).
    ↜ इसके लिए, addEventListener() को { passive: false } से कॉल करना ज़रूरी है.

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

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

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

  • document + "contextमेन्यू" इवेंट: 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 पर टॉम विल्सन की हीरो इमेज.