জাভাস্ক্রিপ্ট ইভেন্টিং গভীর ডুব

preventDefault এবং stopPropagation : কখন ব্যবহার করতে হবে এবং প্রতিটি পদ্ধতি ঠিক কী করে।

Event.stopPropagation() এবং Event.preventDefault()

জাভাস্ক্রিপ্ট ইভেন্ট হ্যান্ডলিং প্রায়ই সোজা। একটি সাধারণ (তুলনামূলকভাবে সমতল) এইচটিএমএল কাঠামোর সাথে কাজ করার সময় এটি বিশেষভাবে সত্য। ঘটনাগুলি যখন উপাদানগুলির একটি শ্রেণিবিন্যাসের মাধ্যমে ভ্রমণ (বা প্রচার) করে তখন জিনিসগুলি আরও কিছুটা জড়িত হয়। এটি সাধারণত হয় যখন ডেভেলপাররা তাদের সম্মুখীন হওয়া সমস্যার সমাধান করতে stopPropagation() এবং/অথবা preventDefault() এর জন্য পৌঁছায়। আপনি যদি কখনও মনে করেন "আমি শুধু preventDefault() চেষ্টা করব এবং যদি এটি কাজ না করে তবে আমি stopPropagation() চেষ্টা করব এবং যদি এটি কাজ না করে, আমি উভয়ই চেষ্টা করব," তাহলে এই নিবন্ধটি তোমার জন্য! প্রতিটি পদ্ধতি ঠিক কী করে, কখন কোনটি ব্যবহার করতে হবে তা আমি ব্যাখ্যা করব এবং অন্বেষণ করার জন্য আপনাকে বিভিন্ন কাজের উদাহরণ প্রদান করব। আমার লক্ষ্য আপনার বিভ্রান্তি একবার এবং সব জন্য শেষ করা.

যদিও আমরা খুব গভীরভাবে ডুব দেওয়ার আগে, জাভাস্ক্রিপ্টে সম্ভাব্য দুটি ধরণের ইভেন্ট পরিচালনার উপর সংক্ষিপ্তভাবে স্পর্শ করা গুরুত্বপূর্ণ (সমস্ত আধুনিক ব্রাউজারে যা হল—সংস্করণ 9 এর আগে ইন্টারনেট এক্সপ্লোরার ইভেন্ট ক্যাপচারিংকে মোটেও সমর্থন করে না)।

ইভেন্টিং শৈলী (ক্যাপচার এবং বুদবুদ)

সমস্ত আধুনিক ব্রাউজার ইভেন্ট ক্যাপচারিং সমর্থন করে, কিন্তু এটি খুব কমই ডেভেলপারদের দ্বারা ব্যবহৃত হয়। মজার বিষয় হল, এটিই ইভেন্টের একমাত্র রূপ যা নেটস্কেপ মূলত সমর্থন করেছিল। নেটস্কেপের সবচেয়ে বড় প্রতিদ্বন্দ্বী, মাইক্রোসফ্ট ইন্টারনেট এক্সপ্লোরার, ইভেন্ট ক্যাপচারিংকে মোটেও সমর্থন করেনি, বরং, শুধুমাত্র ইভেন্ট বুদবুদ নামক ইভেন্টের আরেকটি শৈলীকে সমর্থন করেছিল। যখন W3C গঠিত হয়, তখন তারা ইভেন্টের উভয় শৈলীতে যোগ্যতা খুঁজে পায় এবং ঘোষণা করে যে ব্রাউজারগুলির উভয়কেই সমর্থন করা উচিত, addEventListener পদ্ধতিতে তৃতীয় প্যারামিটারের মাধ্যমে। মূলত, সেই প্যারামিটারটি ছিল একটি বুলিয়ান, কিন্তু সমস্ত আধুনিক ব্রাউজার তৃতীয় প্যারামিটার হিসাবে একটি options অবজেক্টকে সমর্থন করে, যেটি আপনি ইভেন্ট ক্যাপচারিং ব্যবহার করতে চাইলে (অন্যান্য জিনিসগুলির মধ্যে) নির্দিষ্ট করতে ব্যবহার করতে পারেন:

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

নোট করুন যে options অবজেক্টটি ঐচ্ছিক, যেমন এটির capture সম্পত্তি। যদি উভয়টি বাদ দেওয়া হয়, capture জন্য ডিফল্ট মান false , যার অর্থ ইভেন্ট বুদবুদ ব্যবহার করা হবে।

ইভেন্ট ক্যাপচারিং

আপনার ইভেন্ট হ্যান্ডলার যদি "ক্যাপচারিং পর্বে শুনছেন" তাহলে এর অর্থ কী? এটি বোঝার জন্য, আমাদের জানতে হবে কিভাবে ঘটনার উৎপত্তি হয় এবং কিভাবে তারা ভ্রমণ করে। নিম্নলিখিতগুলি সমস্ত ইভেন্টের ক্ষেত্রে সত্য, এমনকি যদি আপনি, বিকাশকারী হিসাবে, এটিকে লাভবান না করেন, এটি সম্পর্কে যত্ন না করেন বা এটি সম্পর্কে ভাবেন।

সমস্ত ইভেন্ট উইন্ডোতে শুরু হয় এবং প্রথমে ক্যাপচারিং পর্বের মধ্য দিয়ে যায়। এর মানে হল যখন একটি ইভেন্ট পাঠানো হয়, এটি উইন্ডোটি শুরু করে এবং প্রথমে তার লক্ষ্য উপাদানের দিকে "নীচে" ভ্রমণ করে। আপনি শুধুমাত্র বুদবুদ পর্যায়ে শুনলেও এটি ঘটে। নিম্নলিখিত উদাহরণ মার্কআপ এবং জাভাস্ক্রিপ্ট বিবেচনা করুন:

<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 শুরু হবে এবং ব্রাউজার নিম্নলিখিত প্রশ্নগুলি জিজ্ঞাসা করবে:

"ক্যাপচারিং পর্বে window ক্লিক ইভেন্টের জন্য কি কিছু শোনা যাচ্ছে?" যদি তাই হয়, উপযুক্ত ইভেন্ট হ্যান্ডলারদের গুলি করা হবে। আমাদের উদাহরণে, কিছুই নেই, তাই কোনো হ্যান্ডলার গুলি করবে না।

এর পরে, ইভেন্টটি document প্রচার করবে এবং ব্রাউজার জিজ্ঞাসা করবে: "ক্যাপচারিং পর্বে document একটি ক্লিক ইভেন্টের জন্য কি কিছু শোনা যাচ্ছে?" যদি তাই হয়, উপযুক্ত ইভেন্ট হ্যান্ডলারদের গুলি করা হবে।

এরপরে, ইভেন্টটি <html> এলিমেন্টে প্রচারিত হবে এবং ব্রাউজার জিজ্ঞাসা করবে: "ক্যাপচারিং পর্বে <html> এলিমেন্টে ক্লিক করার জন্য কি কিছু শোনা যাচ্ছে?" যদি তাই হয়, উপযুক্ত ইভেন্ট হ্যান্ডলারদের গুলি করা হবে।

এরপরে, ইভেন্টটি <body> এলিমেন্টে প্রচারিত হবে এবং ব্রাউজার জিজ্ঞাসা করবে: "ক্যাপচারিং পর্বে <body> এলিমেন্টে ক্লিক ইভেন্টের জন্য কি কিছু শোনা যাচ্ছে?" যদি তাই হয়, উপযুক্ত ইভেন্ট হ্যান্ডলারদের গুলি করা হবে।

এর পরে, ইভেন্টটি #A উপাদানে প্রচারিত হবে। আবার, ব্রাউজার জিজ্ঞাসা করবে: "ক্যাপচারিং পর্বে #A তে একটি ক্লিক ইভেন্টের জন্য কি কিছু শোনা যাচ্ছে এবং যদি তা হয়, তাহলে উপযুক্ত ইভেন্ট হ্যান্ডলাররা ফায়ার করবে।

এর পরে, ইভেন্টটি #B উপাদানে প্রচারিত হবে (এবং একই প্রশ্ন জিজ্ঞাসা করা হবে)।

অবশেষে, ইভেন্টটি তার লক্ষ্যে পৌঁছাবে এবং ব্রাউজার জিজ্ঞাসা করবে: "ক্যাপচারিং পর্বে #C এলিমেন্টে ক্লিক ইভেন্টের জন্য কি কিছু শোনা যাচ্ছে?" এবার উত্তর হল "হ্যাঁ!" এই সংক্ষিপ্ত সময়কাল যখন ইভেন্টটি লক্ষ্যে থাকে, এটি "লক্ষ্য পর্যায়" হিসাবে পরিচিত। এই মুহুর্তে, ইভেন্ট হ্যান্ডলারটি ফায়ার হবে, ব্রাউজারটি console.log করবে "#C ক্লিক করা হয়েছিল" এবং তারপরে আমরা শেষ করেছি, তাই না? ভুল! আমরা মোটেই শেষ করিনি। প্রক্রিয়া চলতে থাকে, কিন্তু এখন এটি বুদবুদ পর্যায়ে পরিবর্তিত হয়।

ইভেন্ট বুদবুদ

ব্রাউজার জিজ্ঞাসা করবে:

"বাবলিং পর্বে কি #C তে ক্লিক ইভেন্টের জন্য কিছু শোনা যাচ্ছে?" এখানে ঘনিষ্ঠ মনোযোগ দিন. ক্যাপচারিং এবং বুদবুদ উভয় পর্যায়েই ক্লিক (বা যেকোনো ইভেন্টের ধরন) শোনা সম্পূর্ণভাবে সম্ভব। এবং যদি আপনি উভয় পর্বে ইভেন্ট হ্যান্ডলারকে ওয়্যার আপ করে থাকেন (যেমন .addEventListener() কে দুবার কল করে, একবার capture = true এবং একবার capture = false দিয়ে), তাহলে হ্যাঁ, উভয় ইভেন্ট হ্যান্ডলার একই উপাদানের জন্য একেবারে ফায়ার করবে। কিন্তু এটাও লক্ষ করা গুরুত্বপূর্ণ যে তারা বিভিন্ন পর্যায়ে ফায়ার করে (একটি ক্যাপচারিং পর্যায়ে এবং একটি বুদবুদ পর্যায়ে)।

এরপরে, ইভেন্টটি প্রচার করবে (সাধারণত "বুদবুদ" হিসাবে বলা হয় কারণ এটি মনে হয় যেন ইভেন্টটি DOM ট্রি থেকে "উপরে" ভ্রমণ করছে) তার মূল উপাদান, #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,
);

কনসোল আউটপুট নির্ভর করবে আপনি কোন উপাদানটি ক্লিক করবেন তার উপর। আপনি যদি 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()

ইভেন্টের উৎপত্তি কোথায় এবং কিভাবে তারা DOM-এর মাধ্যমে ক্যাপচারিং ফেজ এবং বাবলিং ফেজে ভ্রমণ করে (অর্থাৎ প্রচার করে) তা বোঝার সাথে, আমরা এখন আমাদের মনোযোগ 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() দেখতে পান, তখন "ক্রিয়া" শব্দটি যোগ করুন। মনে করুন "ডিফল্ট অ্যাকশন প্রতিরোধ করুন।"

এবং আপনি জিজ্ঞাসা করতে পারেন ডিফল্ট কর্ম কি? দুর্ভাগ্যবশত, এর উত্তরটি পুরোপুরি পরিষ্কার নয় কারণ এটি প্রশ্নে উপাদান + ইভেন্ট সংমিশ্রণের উপর অত্যন্ত নির্ভরশীল। এবং বিষয়গুলিকে আরও বিভ্রান্তিকর করতে, কখনও কখনও কোনও ডিফল্ট অ্যাকশন নেই!

বোঝার জন্য একটি খুব সহজ উদাহরণ দিয়ে শুরু করা যাক। আপনি যখন একটি ওয়েব পৃষ্ঠায় একটি লিঙ্ক ক্লিক করেন তখন আপনি কি ঘটতে আশা করেন? স্পষ্টতই, আপনি আশা করেন যে ব্রাউজারটি সেই লিঙ্ক দ্বারা নির্দিষ্ট URL-এ নেভিগেট করবে। এই ক্ষেত্রে, উপাদানটি একটি অ্যাঙ্কর ট্যাগ এবং ইভেন্টটি একটি ক্লিক ইভেন্ট। সেই সংমিশ্রণে ( <a> + click ) লিঙ্কের href-এ নেভিগেট করার একটি "ডিফল্ট অ্যাকশন" রয়েছে। আপনি যদি ব্রাউজারটিকে সেই ডিফল্ট অ্যাকশনটি সম্পাদন করতে বাধা দিতে চান? অর্থাৎ, ধরুন আপনি <a> এলিমেন্টের href অ্যাট্রিবিউট দ্বারা নির্দিষ্ট URL-এ নেভিগেট করা থেকে ব্রাউজারকে আটকাতে চান? এটিই 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 লেবেলযুক্ত লিঙ্কটিতে ক্লিক করলে www.theavettbrothers.com এ ব্রাউজ করা হবে। যদিও এই ক্ষেত্রে, আমরা একটি ক্লিক ইভেন্ট হ্যান্ডলারকে <a> উপাদানে সংযুক্ত করেছি এবং নির্দিষ্ট করেছি যে ডিফল্ট ক্রিয়াটি প্রতিরোধ করা উচিত। এইভাবে, যখন একজন ব্যবহারকারী এই লিঙ্কে ক্লিক করেন, তখন তারা কোথাও নেভিগেট হবে না, এবং এর পরিবর্তে কনসোলটি কেবল লগ করবে "হয়তো আমাদের এখানে তাদের কিছু সঙ্গীত চালানো উচিত?"

অন্য কোন উপাদান/ইভেন্ট সংমিশ্রণ আপনাকে ডিফল্ট অ্যাকশন প্রতিরোধ করতে দেয়? আমি সম্ভবত তাদের সবগুলি তালিকাভুক্ত করতে পারি না, এবং কখনও কখনও আপনাকে দেখতে পরীক্ষা করতে হবে। তবে সংক্ষেপে, এখানে কয়েকটি রয়েছে:

  • <form> উপাদান + "জমা দিন" ইভেন্ট: এই সংমিশ্রণের জন্য preventDefault() একটি ফর্ম জমা হতে বাধা দেবে। যদি আপনি বৈধতা সম্পাদন করতে চান এবং কিছু ব্যর্থ হলে, আপনি শর্তসাপেক্ষে প্রিভেনড ডিফল্ট কল করতে পারেন যাতে ফর্ম জমা দেওয়া থেকে বিরত থাকে৷

  • <a> element + "click" ইভেন্ট: preventDefault() এই সংমিশ্রণের জন্য ব্রাউজারকে <a> এলিমেন্টের href অ্যাট্রিবিউটে নির্দিষ্ট করা URL-এ নেভিগেট করতে বাধা দেয়।

  • document + "মাউসহুইল" ইভেন্ট: preventDefault() এই সংমিশ্রণের জন্য মাউসহুইল দিয়ে পৃষ্ঠা স্ক্রলিং প্রতিরোধ করে (যদিও কীবোর্ড দিয়ে স্ক্রোল করা এখনও কাজ করবে)।
    ↜ এর জন্য addEventListener() { passive: false } দিয়ে কল করতে হবে

  • document + "কীডাউন" ইভেন্ট: preventDefault() এই সংমিশ্রণের জন্য প্রাণঘাতী। এটি কীবোর্ড স্ক্রোলিং, ট্যাবিং এবং কীবোর্ড হাইলাইটিং প্রতিরোধ করে পৃষ্ঠাটিকে অনেকাংশে অকেজো করে দেয়।

  • document + "মাউসডাউন" ইভেন্ট: এই সংমিশ্রণের জন্য preventDefault() মাউসের সাহায্যে টেক্সট হাইলাইট করা এবং অন্য যেকোন "ডিফল্ট" অ্যাকশনকে আটকাবে যা মাউস ডাউন দিয়ে আহ্বান করবে।

  • <input> element + "keypress" ইভেন্ট: preventDefault() এই সংমিশ্রণের জন্য ব্যবহারকারীর দ্বারা টাইপ করা অক্ষরগুলিকে ইনপুট উপাদানে পৌঁছাতে বাধা দেবে (তবে এটি করবেন না; কদাচিৎ, যদি কখনও, এর জন্য একটি বৈধ কারণ থাকে)।

  • document + "প্রসঙ্গমেনু" ইভেন্ট: এই সংমিশ্রণের জন্য 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() কেও বলি, যা আপনি মনে রাখবেন ডিফল্ট ক্রিয়াকে বাধা দেয়। তাই যেকোনো ডিফল্ট অ্যাকশন (যেমন মাউসহুইল স্ক্রোল, কীবোর্ড স্ক্রোল বা হাইলাইট বা ট্যাবিং, লিঙ্ক ক্লিক করা, প্রসঙ্গ মেনু প্রদর্শন ইত্যাদি) সবই প্রতিরোধ করা হয়, এইভাবে পৃষ্ঠাটিকে মোটামুটি অকেজো অবস্থায় ফেলে দেওয়া হয়।

লাইভ ডেমো

এই নিবন্ধ থেকে সমস্ত উদাহরণ আবার এক জায়গায় অন্বেষণ করতে, নীচে এমবেডেড ডেমো দেখুন।

স্বীকৃতি

আনস্প্ল্যাশে টম উইলসনের হিরো ছবি।