Event در جاوا اسکریپت – راهنمای جامع
رویدادها، اتفاقاتی هستند که درون سیستمی که در حال برنامه نویسی است رخ داده و با توجه به کد واکنشی نشان میدهد. بهعنوان مثال، اگر کاربری روی یکی از دکمههای سایت کلیک کند، اتفاقی رخ داده و یک واکنش در وبسایت مشاهده خواهد کرد. در این مقاله بهطور کامل دربارهی Event در جاوا اسکریپت و نحوهی کار آن در موتورهای جتسجو را بررسی خواهیم کرد.
Event در جاوا اسکریپت چیست؟
رویدادها، واکنشهایی هستند که با کدهای برنامه نویسی اتفاق میافتند. یعنی سیستم سیگنالهایی را در زمان وقوع رویداد تولید کرده و مکانیزمی را فراهم میکند تا در آن اقدامی بهصورت خودکار انجام شود (یعنی اجرای برخی از کدها). Event در جاوا اسکریپت درون پنجرهای نمایش داده میشود و باید آیتمی به درون آن متصل شود. این آیتم ممکن است عنصر تک یا مجموعهای از عناصر بارگیری شده از سند HTML در تب جاری یا کل پنجره مرورگر باشد.
انواع مختلفی از رویدادها که با کلیک در جاوا اسکریپت اتفاق میافتند عبارتاند از:
- کاربر، عنصری خاص را انتخاب کرده، روی آن کلیک میکند یا اشارهگر ماوس روی آن قرار بگیرد.
- رویداد onclick در جاوا اسکریپت، رویدادی است که کاربر روی کلیدی در صفحه کلید، کلیک میکند.
- کاربر پنجره مرورگر را تغییر داده یا آن را میبندد.
- فرمی ارسال شود.
- یک ویدیو پخش، موقف یا تمام شود.
- خطایی رخ دهد.
با توجه به تعداد رویدادهایی که معرفی کردیم، میتوان گفت تعداد رویدادهایی که در جاوا اسکریپت وجود دارند، زیاد است.
برای اینکه کاربر بتواند به رویدادها پاسخ دهد به رویداد گیرنده یا Event handler نیاز دارد. این رویداد بلوک کدی است که برنامه نویس در جاوا اسکریپت ایجاد میکند تا در زمان اجرای رویداد کاربر بتواند واکنشی برای آن ارسال کند.
مثال:
<button>Change color</button>
در این مثال رویدادی به دکمه اضافه شده که با کلیک روی آن، رنگ تغییر میکند. در ادامه نمونه کد Event در جاوا اسکریپت برای تغییر رنگ پسزمینه به رنگ تصادفی را خواهیم دید:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
btn.addEventListener("click", () => {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
});
خروجی مثال فوق به صورت زیر است:
استفاده از addEventListener
شی event در جاوا اسکریپت به متدی خاص نیاز دارد. این متد addEventListener نام دارد و برای اضافه کردن رویدادهای گیرندهها استفاده میشود. نگاهی دقیقتر به مثال قبل:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
btn.addEventListener("click", () => {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
});
عنصر <button> در HTML، رویدادی را تعریف میکند که در زمان کلیک کردن روی آن، اجرا میشود. این رویداد توسط تابع ()addEventListener تعریف میشود و در زمان مشخص فراخوانی میشود. در این مثال دو پارامتر ارسال میشوند که عبارتاند از:
- click: این رشته برای نشان دادن این است که میخواهیم به رویداد کلیک گوش دهیم. گفتنی است که دکمهها میتوانند رویدادهای دیگری مانند mouseover (که با حرکت ماوس روی دکمه رویدادی رخ میدهد) و keydown (که با زدن یک دکمه اتفاقی رخ میدهد) را انجام دهند.
- تابع RGB: تابعی است که در Event در جاوا اسکریپت وجود دارد و باعث تولید رنگ تصادفی در پس زمینه میشود.
نمونه کد برای نامگذاری:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
function changeBackground() {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
}
btn.addEventListener("click", changeBackground);
پیشنهاد مطالعه: آموزش Var در جاوا اسکریپت به زبان ساده
گوش دادن به رویدادهای دیگر در addEventListener
رویدادهای زیادی وجود دارند که توسط شی event در جاوا اسکریپت اجرا میشوند. در برنامه نویسی جاوا اسکریپت میتوان برای رویداد click ارزشهای مختلفی ایجاد کرد، مانند:
- focus و blur: این رویدادها برای کانونی شدن دکمهها عمل میکنند. یعنی با استفاده از کلید Tab دکمه کانونی شده و با فشار مجدد Tab از حالت کانونی خارج میشود. از این رویداد برای زمانی استفاده میشود که اطلاعات پر شده در فرم اشتباه است و میخواهید اطلاعات درست آن را به کاربر نشان دهید.
- Dblclick: این شی event در جاوا اسکریپت زمانی اجرا میشود که روی دکمه دوبار کلیک شود.
برخی از Event در جاوا اسکریپت مانند click برای بیشتر عناصر وجود دارند و کاربرد زیادی دارند. برخی دیگر از رویدادها مانند play وجود دارند که در زمانهایی خاص برای عنصر <video> کاربرد دارند.
نحوهی حذف کردن گوش دهندهها
زمانی که به رویداد اضافه شده توسط addEventListener در جاوا اسکریپت نیاز ندارید میتوانید آن را با استفاده از متد removeEventListener حذف کنید. مثالی برای حذف کردن changeBackground:
btn.removeEventListener("click", changeBackground);
زمانی که رویدادهایی که میتوانند AbortSignal به ()addEventListener ارسال کنند، سپس فراخوانی را با ()abort که در کنترلر به AbortSignal متعلق است را حذف کرد. نمونه کد زیر نشان میدهد که چگونه میتوان رویداد گیرنده را با استفاده از AbortSignal حذف کرد:
const controller = new AbortController();
btn.addEventListener("click",
() => {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
},
{ signal: controller.signal } // pass an AbortSignal to this handler
);
برای حذف کد بالا به این صورت عمل میکنیم:
controller.abort(); // removes any/all event handlers associated with this controller
در این مثال ()controller.abort رویداد کنترلر را حذف میکند.
در برنامههایی که ساده و کوچک هستند، پاک کردن گیرندههای رویداد قدیمی و استفاده نشده ضروری نیست. پاک کردن این گیرندهها زمانی اهمیت دارند که برنامهها بزرگ و پیچیده هستند. زیرا این کار به بهبود عملکرد و کارایی برنامه کمک میکند.
پیشنهاد مطالعه: Const در جاوا اسکریپت: نگهبان مقادیر شما در دنیای متغیر
افزودن چندین گوش دهنده برای یک رویداد تکی
با چند فراخوانی ()addEventListener و ارائه گیرندههای مختلف میتوانید چند گیرنده رویداد تکی داشته باشید:
myElement.addEventListener("click", functionA);
myElement.addEventListener("click", functionB);
هر دوی این توابع زمانی که روی عنصر کلیک شود، اجرا خواهند شد.
مکانیزمهای دیگر گوش دهنده رویداد
در ()addEventListener که Event در جاوا اسکریپت است برای ثبت گیرندههای رویداد استفاده میشود. این یکی از قدرتمندترین روشها است که برای برنامههای پیچیده مقیاسپذیری خوبی دارد.
گفتنی است که دو روش دیگر برای ثبت وجود دارد که عبارتاند از خصوصیتهای گیرنده رویداد و گیرندههای رویداد درون خطی گیرندههای رویداد در ادامه آنها را شرح دادهایم:
خصوصیتهای گیرنده رویداد:
این Event object در جاوا اسکریپت میتواند رویدادها را اجرا کند و اغلب خصوصیتهایی دارد که در نام آنها کلمه on همراه با نام رویداد میآید. بهعنوان مثال رویداد onclick در جاوا اسکریپت یکی از خصوصیتهای گیرنده رویداد است. مثال:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
btn.onclick = () => {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
};
برای اختصاص خصوصیت گیرنده به تابع نامگذاری در Event در جاوا اسکریپت مانند زیر باید عمل کرد:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
function bgChange() {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
}
btn.onclick = bgChange;
گفتنی است که با استفاده از خصوصیتهای رویداد شما نمیتوانید بیش از یک گیرنده به رویداد تکی اضافه کنید.
element.addEventListener("click", function1);
element.addEventListener("click", function2);
این کار با خصوصیتهای گیرنده رویداد غیرممکن خواهد بود، به همین علت موارد قبلی باید بهصورت زیر بازنویسی شوند:
element.onclick = function1;
element.onclick = function2;
در بالا صفات واقعی بهصورت واقعی در کد جاوا اسکریپ نشان داده شده است که میخواهید در زمان وقوع رویداد اجرا شود. شما مانند مثال زیر میتوانید Event در جاوا اسکریپت را بهصورت مستقیم درون صفت وارد کنید:
<button onclick="bgChange()">Press me</button>
به این نکته توجه کنید که نباید از صفات HTML در جاوا اسکریپت استفاده کنید و باید به دنبال معادلهای آنها باشید. این صفات گیرنده رویداد که تبدیل میشوند کمک میکنند تا سرعت انجام کارهای شما افزایش پیدا کرده و آسانتر انجام شوند.
گیرندههای رویداد درون خطر جاوا اسکریپت بهعنوان اقدامات امنیتی استفاده میشوند و عملکردی خوب دارند، اما به این نکته باید توجه کنید که از صفات گیرنده رویداد HTML به علت منسوخ شدن نباید استفاده کنید.
const buttons = document.querySelectorAll("button");
for (const button of buttons) {
button.addEventListener("click", bgChange);
}
اشیاء رویداد
برخی اوقات تابع گیرندهای با نامی مانند Event در جاوا اسکریپت مشاهده میشود که به آنها شی event در جاوا اسکریپت گفته میشود. این شیها بهصورت خودکار برای گیرندههای رویداد ارسال میشوند تا ویژگیها و اطلاعات بیشتر را فراهم کنند. مثال:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
function bgChange(e) {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
e.target.style.backgroundColor = rndCol;
console.log(e);
}
btn.addEventListener("click", bgChange);
در این مثال میبینید که e شی رویداد است و در تابع سبک رنگ پسزمینه روی e.target تعریف شده است. این دکمه با توجه به خصوصیتی که شی event.target در جاوا اسکریپت مشخص کرده رویدادی را انجام میدهد که در این مثال بهصورت تصادفی رنگ پسزمینه تغییر میکند.
خصوصیتهای اضافی اشیاء رویداد
بیشتر Event targetها مجموعهای استاندارد از خصوصیتها و متدهای در دسترس روی شیء رویداد هستند. برخی از اشیاء رویداد خصوصیتهای اضافی را اضافه میکنند که مربوط به نوع خاصی از رویداد است. بهعنوان مثال، رویداد keydown زمانی اجرا خواهد شد که کاربر کلید یا دکمهای را فشار میدهد. شیء رویداد آن یک KeyboardEvent است،که شیء Event تخصصی با یک خصوصیت key بوده که به شما میگوید کدام کلید فشرده شده است:
<input id="textBox" type="text" />
<div id="output"></div>
const textBox = document.querySelector("#textBox");
const output = document.querySelector("#output");
textBox.addEventListener("keydown", (event) => {
output.textContent = `You pressed "${event.key}".`;
});
خروجی مثال فوق به صورت زیر است:
جلوگیری از رفتار پیش فرض
در برخی مواقع موقعیتی بهوجود میآید که قصد دارید از انجام رویدادهای پیش فرض جلوگیری کنید. بهعنوان مثال میتوان گفت زمانی که فرمی برای پر کردن در سایت وجود دارد که کاربران باید آن را پر کرده و دکمه ارسال را وارد کنند تا با پیغام اطلاعات با موفقیت ثبت شد، روبهرو شوند. اما، توسعهدهنگان باید از وارد کردن اطلاعات نادرست و ثبت آنها در پایگاه داده جلوگیری کنند، به همین علت زمانی که اطلاعات نادرست است با زدن دکمه ارسال باید پیغام خطا به کاربر نمایش داده شود و به اون نشان دهند که چه فیلدی از اطلاعات اشتباه است.
مثال ایجاد کردن فرم اطلاعات:
<form>
<div>
<label for="fname">First name: </label>
<input id="fname" type="text" />
</div>
<div>
<label for="lname">Last name: </label>
<input id="lname" type="text" />
</div>
<div>
<input id="submit" type="submit" />
</div>
</form>
<p></p>
حالا با استفاده از دستورات زیر بررسی میتوان بررسی کرد که فیلدی خالی است یا خیر. برای این کار از تابع ()preventDefault برای فراخوانی شی استفاده کرده تا اگر فیلدی خالی بود پیغام درستی را نمایش دهد.
const form = document.querySelector("form");
const fname = document.getElementById("fname");
const lname = document.getElementById("lname");
const para = document.querySelector("p");
form.addEventListener("submit", (e) => {
if (fname.value === "" || lname.value === "") {
e.preventDefault();
para.textContent = "You need to fill in both names!";
}
});
خروجی مثال فوق هم به صورت زیر است:
انتشار حباب رویداد (Event bubbling)
Event bubbling، توصیف میکند که چگونه مرورگر میتواند با رویدادهایی که عناصر تو در تو دارند، برخورد کند. مثال تنظیم گوشدهنده بهعنوان عنصر والد:
<div id="container">
<button>Click me!</button>
</div>
<pre id="output"></pre>
در این مثال عنصر <div> در داخل عنصر دیگری قرار دارد که در اصطلاح عنصر والد نام دارد. اگر گیرندهی رویداد کلیک را به والد آن اضافه کنیم و سپس روی دکمه کلیک کنیم، Event در جاوا اسکریپت مانند قطعه کد زیر میشود:
const output = document.querySelector("#output");
function handleClick(e) {
output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}
const container = document.querySelector("#container");
container.addEventListener("click", handleClick);
خروجی مثال فوق هم به صورت زیر است:
مثالی دیگر از انتشار حباب:
پیشنهاد مطالعه: مقایسه دو آرایه در جاوا اسکریپت: یک راهنمای جامع
اضافه گوشدهنده رویداد به دکمه والد:
<body>
<div id="container">
<button>Click me!</button>
</div>
<pre id="output"></pre>
</body>
برای اضافه کردن والد (<div>) و عنصر <body> به گیرندههای رویداد کلیک باید مانند زیر عمل کنیم:
const output = document.querySelector("#output");
function handleClick(e) {
output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}
const container = document.querySelector("#container");
const button = document.querySelector("button");
document.body.addEventListener("click", handleClick);
container.addEventListener("click", handleClick);
button.addEventListener("click", handleClick);
خروجی این مثال هم به صورت زیر است:
در این مثال قصد داریم زمانی که کاربر روی دکمه کلیک میکند هر سه عنصر یک رویداد را فرخوانی کنند، بعنی:
- با کلیک دکمه اول فراخوانی میشود.
- بهدنبال آن کلیک روی والد یعنی عنصر <div> انجام میشود.
- سپس عنصر والد <div> که <body> است فراخوانی خواهد شد.
این فراخوانی از درونیترین عنصر شروع شده تا به اولین عنصر کلیک شده برسد. این رفتار در برخی میتواند مفید باید و در بعضی مواقع میتواند مشکلساز شود.
رفع مشکل با استفاده از تابع stopPropagation
در بخش قبل گفتیم که Event bubbling گاهی اوقات میتواند مشکلاتی بهوجود آورد. Event در جاوا اسکریپت تابعی به نام ()stopPropagation دارد که میتواند از بهوجود آمدن این مشکلات جلوگیری کند. عملکرد این تابع به این صورت است که داخل گیرنده رویداد فراخوانی شده و از انتشار رویداد در سایر عناصر جلوگیری میکند.
مشکل Event bubbling با استفاده از کد زیر برطرف میشود:
const btn = document.querySelector("button");
const box = document.querySelector("div");
const video = document.querySelector("video");
btn.addEventListener("click", () => box.classList.remove("hidden"));
video.addEventListener("click", (event) => {
event.stopPropagation();
video.play();
});
box.addEventListener("click", () => box.classList.add("hidden"));
گسترش رویداد (Event Capture) با Event در جاوا اسکریپت
شکل دیگری از جایگزین انتشار رویداد، گسترش رویداد است. Event Capture مانند انتشار حباب بوده اما با ترتیب برعکس. یعنی رویداد بهجای اینکه در درونیترین عنصر هدف فراخوانی شود، در بیرونیتریم عنصر هدف فراخوانی میشود. این متد بهصورت پیش فرض غیرفعال بوده و برای فعال کردن آن باید در ()addEventListener گزینهی capture ارسال شود. مثال:
<body>
<div id="container">
<button>Click me!</button>
</div>
<pre id="output"></pre>
</body>
const output = document.querySelector("#output");
function handleClick(e) {
output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}
const container = document.querySelector("#container");
const button = document.querySelector("button");
document.body.addEventListener("click", handleClick, { capture: true });
container.addEventListener("click", handleClick, { capture: true });
button.addEventListener("click", handleClick);
خروجی مثال فوق به صورت زیر است:
در این مورد، ترتیب پیامها برعکس است. یعنی در ابتدا رویداد <body> اجرا میشود، سپس رویداد <div> و در نهایت رویداد <button>.
انتقال رویداد Event delegation
گسترش رویداد برای Event delegation بسیار مفید است. زیرا با استفاده آن میتوان زمانی که قصد داریم کدی را در زمان تعامل کاربر، رویدادهایی که در عناصر فرزند روخ میدهند را بهصورت مستقیم گسترش دهیم و آنها را بهصورت جداگانه مدیریت نکنیم. مثال:
<div id="container">
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
در ادامه از کدهای CSS برای تنظیم اندازه و موقعیتها باید استفاده کنیم:
.tile {
height: 100px;
width: 25%;
float: left;
}
حالا میتوان برای Event در جاوا اسکریپت، مدیر رویداد کلیک برای هر بخش اضافه کرد. اما گزینه کارآمد و ساده این است که مدیر رویداد کلیک را روی عنصر والد تنظیم کرده تا از گسترش رویداد برای اطمینان از اجرای مدیر در زمانی که کاربر روی بخشی کلیک میکند استفاده کنیم. مانند کد زیر:
function random(number) {
return Math.floor(Math.random() * number);
}
function bgChange() {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
return rndCol;
}
const container = document.querySelector("#container");
container.addEventListener("click", (event) => {
event.target.style.backgroundColor = bgChange();
});
خروجی مثال فوق به صورت زیر است:
توجه کنید که در مثال فوق از event.target در جاوا اسکریپت برای دستیابی به عنصری که هدف آن فراخوانی رویداد بوده استفاده کردهایم.
رویدادها و Event در جاوا اسکریپت رویدادها فراتر از صفحات وب
مهم است بدانیم که رویدادها صرفاً محدود به زبان برنامه نویسی جاوا اسکریپت و صفحات وب نیستند. اکثر زبانهای برنامه نویسی دارای مدل رویدادی هستند، گرچه نحوهی عملکرد آنها ممکن است با رویدادهای جاوا اسکریپت در صفحات وب متفاوت باشد. بهعنوان مثال، Node.js که یک محیط اجرایی جاوا اسکریپت بسیار محبوب برای توسعه برنامههای شبکه و سرور است، از مدل رویدادی متفاوتی استفاده میکند که بر پایه گوشدهندهها (listeners) و فرستندهها (emitters) استوار است.
همچنین میتوانید از جاوا اسکریپت برای ساخت افزونههای میانمرورگری با استفاده از فناوری WebExtensions استفاده کنید. مدل رویدادی در این حوزه نیز شباهتهایی با رویدادهای وب دارد، اما تفاوتهایی نیز وجود دارد.
سخن پایانی
در این مقاله، مبانی Event در جاوا اسکریپت در محیط وب را فرا گرفتید. رویدادها بخش جداییناپذیری از Web APIهای مرورگر هستند و نقش مهمی در ایجاد رابطهای کاربری پویا و تعاملی ایفا میکنند. درک صحیح مفاهیمی مانند ثبت گوشدهندههای رویداد، انتشار حباب، انتقال رویداد و جلوگیری از رفتار پیشفرض به شما در پیادهسازی عملکردهای پیچیدهتر در اپلیکیشنهای تحت وب کمک خواهد کرد.
در نهایت، مهم است به یاد داشته باشید که مدل رویدادی در حوزههای مختلف برنامه نویسی جاوا اسکریپت، از جمله Node.js و WebExtensions ممکن است با رویدادهای وب متفاوت باشد. با این حال، درک مبانی رویدادها در محیط وب، گام مهمی در مسیر یادگیری و توسعه مهارتهای شما در این زبان قدرتمند خواهد بود.
پیشنهاد مطالعه: Map در جاوا اسکریپت – آموزش مپ به صورت ساده و کامل
یادگیری Event در جاوا اسکریپت با مکتب خونه
به دلیل اهمیت Event در جاوا اسکریپت مکتب خونه دورهی آموزش جاوا اسکریپت را برگزار کرده است. در این دوره مباحثی چون Event loop، Event propagation و Call stack بهطور کامل آموزش داده شده است. در آموزشهایی که مکتب خونه برای جاوا اسکریپت در نظر گرفته است بهطور کامل با Clientx در جاوا اسکریپت آشنا خواهید شد. شما میتوانید بدون محدودیت مکانی در این دورههای آموزش جاوا اسکریپت و آموزش برنامه نویسی از مکتب خونه شرکت کنید. زیرا آموزش جاوا اسکریپت بهصورت آنلاین برگزار میشود.