در این مطلب آموزشی قصد داریم با استفاده از جاوااسکریپت و رویدادهای ماوس یک چیز جالب و مفید را درست کنیم: قصد داریم تصاویر بندانگشتی را ایجاد کنیم که با هاور کردن ماوس در یک قسمت تغییر میکند و تصاویر مختلفی را نشان میدهد.
این مورد نیز یک دمو ساده از چیزی که قرار است ایجاد کنیم (ماوس را روی قسمتهای مختلف هر کدام از کتابهای زیر بگردانید تا تصاویر مختلف را مشاهده کنید):
تصاویر هرکدام از این قسمتها براساس موقعیت ماوس تغییر پیدا میکنند. در طراحی و ساخت این مورد ما از سیستم گریدبندی CSS استفاده میکنیم و رویداد mousemove جاوااسکریپت را به کار میگیریم. البته در کنار این مورد چیزهای دیگری را نیز استفاده میکنیم که در ادامه با آنها آشنایی پیدا خواهید کرد:
۱. نشانهگذاری HTML
این قسمت از نشانهگذاری که ما از آن استفاده میکنیم بسیار ساده است، یک لیست نامرتب ساده و چند تصویر همراه با لیست آیتمها. در حقیقت قصد داریم تا یکسری کاردها را در این قسمت ایجاد نماییم.
<ul class="cards">
<li class="card">
<img src="IMG_SRC" alt="">
<!-- 4 more images here -->
</li> شنبه
<li class="card">
<img src="IMG_SRC" alt="">
<!-- 3 more images here -->
</li>
<li class="card">
<img src="IMG_SRC" alt="">
<!-- 2 more images here -->
</li>
<li class="card">
<img src="IMG_SRC" alt="">
<!-- 1 more image here -->
</li>
</ul>
۲. قسمت CSS
حال با استفاده از این استایلهای CSS میخواهیم به طرحمان استایل بدهیم، اما قبل از آن دو چیز مهم:
- ما لیست نامرتب را به عنوان یک container برای گرید در نظر میگیریم و به لیست آیتمها width:25% را میدهیم. بجای این تکنیک میتوانید از flexbox نیز استفاده کنید.
- ما به صورت بصری تمام تصاویر داخل لیست را مخفی میکنیم.
دستورات سیاساسی که قصد داریم آنها را اضافه نماییم به صورت زیر هستند:
.cards {
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(4, 1fr);
}
.card {
position: relative;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.5);
}
.card:hover {
cursor: pointer;
}
.card img:not(:first-of-type) {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
}
.card img.is-visible {
opacity: 1;
}
در کنار استایلهای دیگری که استفاده میشود (حذف علامت لیست نامرتب، اضافه کردن پس زمینه و...)، خروجی تا به این مرحله به صورت زیر درآمده است:
۳. جاوااسکریپت
در ادامه باید دو خط زیر را به پروژه اضافه کنیم، با اضافه کردن این دو خط، وقتی تمام پروژه به صورت کامل آماده شد، تابع مربوط به init اجرا خواهد شد. همچنین هروقت که اندازه صفحه مرورگر تغییر پیدا کرد این تابع دوباره فراخوانی میشود:
window.addEventListener("load", init);
window.addEventListener("resize", init);
داخل تابع init موارد مختلفی اتفاق میافتد، ابتدا از همه به داخل کاردهایی که ایجاد کردیم دسترسی پیدا میکنیم:
function init() {
const cards = document.querySelectorAll(".card");
cards.forEach(el => {
// actions here
});
}
حال در این مرحله قصد داریم که تعداد تصاویر فرزند را حساب کنیم، البته این مورد بدون در نظر گرفتن تصویر اول انجام میشود:
const numOfChildImages = el.querySelectorAll("img:not(:first-of-type)").length;
اگر در این مرحله حداقل یک تصویر فرزند وجود داشته باشد، ما کارهای زیر را انجام میدهیم:
- عرض کارد را محاسبه میکنیم، عرض اولین تصویر و…
- کارد را به قسمت مساوی براساس تعداد تصاویر تقسیم میکنیم.
if (numOfChildImages > 0) {
const { width } = el.getBoundingClientRect();
const parts = width / numOfChildImages;
}
برای اینکه این موضوع را بهتر درک کنید، یک مربع را در نظر بگیرید که قرار است در چهار قسمت آن تصاویری قرار بگیرد، برای اینکار نیاز است که مربع را به چهار قسمت مساوی تقسیم کنیم، حال کاری که ما قصد داریم انجام دهیم این است که وقتی اشارهگر ماوس روی یک قسمت از مربع قرار گرفت، برای مثال قسمت سوم از مربع، تصویر سوم بارگذاری شود (تصویر آن نمایش داده شود). برای درک بهتر قضیه میتوانید تصویر زیر را مشاهده کنید.
حال که ما کلیت ماجرا را متوجه شدیم، بیایید آن ها را به کد تبدیل کنیم. در قسمت حلقه ما نیاز داریم که رویداد mousemove را فراخوانی کنیم:
// hover cards
el.addEventListener("mousemove", e => {
// do stuff here
});
وقتی این رویداد اجرا شد، ما کارهای زیر را انجام میدهیم:
- مختصات X مربوط به اشارهگر ماوس را دریافت میکنیم.
- کلاس is-visible را از تصاویر کارد حذف میکنیم.
- براساس موقعیت ماوس، تصویر مناسب را نمایش میدهیم.
el.addEventListener("mousemove", e => {
//1
const xPos = e.pageX - el.offsetLeft;
//2
removeIsVisibleClass();
//3
switch (numOfChildImages) {
case 1:
if (xPos > 0 && xPos <= parts) {
addClass(el, "img:nth-child(2)");
}
break;
case 2:
if (xPos > 0 && xPos <= parts) {
addClass(el, "img:nth-child(2)");
} else if (xPos > parts && xPos <= parts * 2) {
addClass(el, "img:nth-child(3)");
}
break;
// more cases below
}
});
همانطور که مشاهده میکنید، دو تابع سفارشی ایجاد شده است. یکی با نام removeIsVisibleClass که مسئول حذف کردن کلاس is-visible است و دومی تابع addClass که مسئول اضافه کردن کلاس is-visible به تصویر مورد نظر است.
برای مشاهده تابعها میتوانید کدهای زیر را نگاه کنید:
function removeIsVisibleClass() {
if (document.querySelector("img.is-visible")) {
document.querySelector("img.is-visible").classList.remove("is-visible");
}
}
function addClass(parent, child, className = "is-visible") {
parent.querySelector(child).classList.add(className);
}
حال که تقریبا پروژه ما تمام است یک قسمت دیگر میماند و آن این است که اگر ماوس را hover نکنیم چه اتفاقی میافتد، برای این کار باید قطعه کد زیر را به پروژه اضافه نماییم:
// inside cards loop
el.addEventListener("mouseleave", () => {
removeIsVisibleClass();
});
خروجی نهایی پروژه باید چیزی شبیه به زیر باشد:
۴. پشتیبانی مرورگر
پیشنمایش پروژه ما باید به خوبی در مرورگرهای مختلف کار کند. اما یکسری نکات که ارزش خواندن دارند:
- در این پروژه ما از CSS Grid و حلقه foreach استفاده کردیم، که در حال حاضر در تمام مرورگرها پشتیبانی نمیشود. نکته مهم این است که برای هر دو مورد جایگزینهایی در نظر گرفته شده است.
- پیشنمایشی که ما ایجاد کردهایم روی تمام صفحات به یک صورت به نمایش درمیآید، بنابراین برای صفحاتی کوچکتر بهینهسازی نشده است. برای پروژه ما ممکن است این موضوع مشکلی نداشته باشد، اما در یک پروژه واقعی باید این مسئله را مد نظر بگیرید.
- در نهایت مانند همیشه ما از Babel برای کامپایل ES6 به ES5 استفاده کردیم.
در پایان
در این آموزش ما از افکت hover و قدرت جاوااسکریپت استفاده کردیم، تا بتوانیم چنین چیز جذابی را ایجاد کنیم. خوشبختانه ما از ایجاد چنین چیزی میتوانیم برای دیگر پروژهها الهام بگیریم.
برای اینکه بیشتر کدها را بهینه کنید، من پیشنهاد میکنم که تابعهایی با قابلیت استفاده مجدد ایجاد کنید تا بتوانید کدهای بهتری را ارائه دهید.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید