بازگشت به درس

تولتیپ "باهوش"

اهمیت: 5

تابعی بنویسید که یک تولتیپ را فقط در صورتی نمایش دهد که کاربر اشاره‌گر موس را داخل آن ببرد و نه اینکه از روی آن فقط عبور کند.

به عبارت دیگر، اگر که کاربر اشاره‌گر موس را روی عنصر ببرد و آنجا متوقف شود، تولتیپ نمایش داده شود. و اگر موس از روی عنصر عبور کرد، نیازی به نمایش تولتیپ نیست. چه کسی یک به تولتیپ لحظه‌ای نیاز دارد؟

از نظر فنی، می‌توانیم سرعت اشاره‌گر موس را روی عنصر اندازه بگیریم، و اگر آرام باشد فرض کنیم که اشاره‌گر “روی عنصر قرار گرفته” و تولتیپ را نمایش دهیم. اگر سریع بود، آنرا نادیده بگیریم.

برای این منظور یک شئ گلوبال به صورت new HoverIntent(options) بسازید.

خصوصیات options:

  • elem – عنصری که می‌خواهیم حرکت اشاره‌گر را روی آن کنترل کنیم.
  • over – تابعی که در صورت “قرار گرفتن اشاره‌گر روی عنصر” صدا زده می‌شود: که یعنی حرکت اشاره‌گر موس کند بوده، یا روی عنصر توقف کرده.
  • out – تابعی که زمانی اشاره‌گر موس عنصر را ترک می‌کند صدا زده‌ می‌شود. (اگر تابع over صدا زده شده باشد).

یک مثال از چگونگی استفاده از چنین شئ برای تولتیپ این چنین خواهد بود:

// تولتیپ نمونه
let tooltip = document.createElement('div');
tooltip.className = "tooltip";
tooltip.innerHTML = "Tooltip";

// این شئ حرکت اشاره‌گر موس را دنبال و توابع over/out را صدا می‌زند.
new HoverIntent({
  elem,
  over() {
    tooltip.style.left = elem.getBoundingClientRect().left + 'px';
    tooltip.style.top = elem.getBoundingClientRect().bottom + 5 + 'px';
    document.body.append(tooltip);
  },
  out() {
    tooltip.remove();
  }
});

دمو:

اگر که اشاره‌گر موس را سریعا از روی “ساعت” حرکت دهید، اتفاقی نمی‌افتد، اگر چه در صورتی که حرکت اشاره‌گر موس آهسته باشد یا روی آن توقف کنید، یک تولتیپ نمایش داده می‌شود.

توجه: تولتیپ نباید هنگامی که اشاره‌گر روی فرزندان ساعت حرکت می‌کند رفتار “چشمک زن” داشته باشد.

باز کردن یک sandbox همراه با تست‌ها.

الگوریتم ساده به نظر می‌رسد:

  1. برای رویدادهای onmouseover/out کنترل‌کننده‌هایی روی عنصر تعریف می‌کنیم. همچنین می‌توانیم از ‍‍‍onmouseenter/leave نیز در این مورد استفاده کنیم، اما کمتر استفاده می‌شوند. درصورتی که از واگذاری رویدادها استفاده کنیم، کار نمی‌کنند.
  2. زمانی که اشاره‌گر موس وارد یک عنصر می‌شود، سرعت آن را در mousemove محاسبه می‌کنیم.
  3. اگر سرعت حرکت آن کند باشد، تابع over را صدا می‌زنیم.
  4. زمانی که از عنصر خارج می‌شویم، و over صدا زده شده بود، تابع out‌ را نیز صدا می‌زنیم.

اما چگونه سرعت اشاره‌گر موس را اندازه گیری کنیم؟

اولین چیزی که به ذهن می‌رسد این است که: یک تابع را هر ‍100ms‍ اجرا کنیم و مسافتی که بین مختصات قبلی و جدید طی شده را اندازه بگیریم. اگر کوچک باشد، پس سرعت حرکت اشاره‌گر موس کند بوده.

متاسفانه راهی برای گرفتن “مختصات فعلی اشاره‌گر موس” در جاوا اسکریپت وجود ندارد. هیچ تابع از قبل آماده‌ای مانند getCurrentMouseCoordiantes() وجود ندارد.

تنها راه برای گرفتن مختصات گوش دادن به رویدادهای موس مانند mousemove و گرفتن مختصات از شئ event خواهد بود.

درنتیجه باید برای رویداد mousemove یک کنترل‌کننده تعریف می‌کنیم تا مختصات را ذخیره کنیم، و آنها را هر 100ms مقایسه کنیم.

پی‌نوشت: توجه کنید که برای آزمایش راه حل از dispatchEvent استفاده می‌شود تا ببیند تولتیپ به درستی کار می‌کند یا نه.

باز کردن راه‌حل همراه با تست‌ها درون یک sandbox.