בעבר היה קל להצביע על דברים באינטרנט. היה לכם עכבר, העברתם אותו, לפעמים לחצתם על לחצנים, וזה היה זה. כל מה שלא היה עכבר הועתק כעכבר, והמפתחים ידעו בדיוק על מה להסתמך.
עם זאת, פשוט לא בהכרח אומר טוב. עם הזמן, התברר שחשוב לא להשתמש רק בעכבר: אפשר להשתמש בעטים עם חיישן לחץ וחיישן הטיה כדי ליהנות מחופש יצירתי מדהים, אפשר להשתמש באצבעות כדי ליהנות מכל מה שצריך הוא המכשיר והיד, ואפשר גם להשתמש ביותר מאצבע אחת.
כבר הרבה זמן יש לנו אירועי מגע שיעזרו לנו בכך, אבל הם ממשק API נפרד לגמרי שמיועד במיוחד למגע. לכן, אם רוצים לתמוך גם בעכבר וגם במגע, צריך לכתוב קוד של שני מודלים נפרדים של אירועים. גרסת Chrome 55 מגיעה עם תקן חדש יותר שמאחד את שני המודלים: אירועי סמן.
מודל של אירוע יחיד
אירועי סמן מאחדים את מודל הקלט של הסמן בדפדפן, ומקבצים יחד מגע, עטים ועכברים לקבוצה אחת של אירועים. לדוגמה:
document.addEventListener('pointermove',
ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
ev => console.log('The pointer is now over foo.'));
לפניכם רשימה של כל האירועים הזמינים, שדומים מאוד לאירועי העכבר:
pointerover
|
הסמן נכנס לתיבת הגבול של הרכיב.
האירוע הזה מתרחש באופן מיידי במכשירים שתומכים בהחזקה מעל, או לפני אירוע pointerdown במכשירים שלא תומכים בהחזקה מעל.
|
pointerenter
|
דומה ל-pointerover , אבל לא עולה למעלה (bubble) ומטפל בצאצאים באופן שונה.
פרטים על המפרט
|
pointerdown
|
הסמן נכנס למצב לחצן פעיל, כשלוחצים על לחצן או כאשר מתקיים מגע, בהתאם לסמנטיקה של מכשיר הקלט. |
pointermove
|
הסמן שינה מיקום. |
pointerup
|
הסמן עזב את מצב הלחצן הפעיל. |
pointercancel
|
קרה משהו שגורם לכך שסביר להניח שהעכבר לא יפיק אירועים נוספים. כלומר, צריך לבטל את כל הפעולות שבתהליך ולחזור למצב קלט נייטרלי. |
pointerout
|
הסמן יצא מתיבת הגבול של האובייקט או המסך. גם אחרי pointerup , אם המכשיר לא תומך בהחזקה מעל.
|
pointerleave
|
דומה ל-pointerout , אבל לא עולה למעלה (bubble) ומטפל בצאצאים באופן שונה.
פרטים על המפרט
|
gotpointercapture
|
הרכיב קיבל צילום של סמן. |
lostpointercapture
|
הפונקציה שתועדה שוחררה. |
סוגי קלט שונים
באופן כללי, אירועי Pointer מאפשרים לכתוב קוד באופן לא תלוי-קלט, בלי צורך לרשום מנהלים נפרדים של אירועים למכשירי קלט שונים.
כמובן, עדיין תצטרכו לשים לב להבדלים בין סוגי הקלט, למשל אם המושג 'החזקה מעל' רלוונטי. אם אתם רוצים להבדיל בין סוגים שונים של מכשירי קלט – אולי כדי לספק קוד או פונקציונליות נפרדים לקלטים שונים – תוכלו לעשות זאת בתוך אותם פונקציות לטיפול באירועים באמצעות המאפיין pointerType
של הממשק PointerEvent
. לדוגמה, אם תכנתם תפריט צדדי, תוכלו להשתמש באירוע pointermove
עם הלוגיקה הבאה:
switch(ev.pointerType) {
case 'mouse':
// Do nothing.
break;
case 'touch':
// Allow drag gesture.
break;
case 'pen':
// Also allow drag gesture.
break;
default:
// Getting an empty string means the browser doesn't know
// what device type it is. Let's assume mouse and do nothing.
break;
}
פעולות ברירת מחדל
בדפדפנים עם תמיכה במגע, תנועות מסוימות משמשות לגלילה, לשינוי מרחק התצוגה או לרענון הדף.
במקרה של אירועי מגע, עדיין תקבלו אירועים בזמן שהפעולות שמוגדרות כברירת מחדל מתבצעות – לדוגמה, האירוע touchmove
עדיין יופעל בזמן שהמשתמש גולל.
כשמשתמשים באירועי סמן, בכל פעם שמופעל פעולת ברירת מחדל כמו גלילה או הגדלת התצוגה, מתקבל אירוע pointercancel
כדי להודיע לכם שהדפדפן השתלט על הסמן. לדוגמה:
document.addEventListener('pointercancel',
ev => console.log('Go home, the browser is in charge now.'));
מהירות מובנית: המודל הזה מאפשר ביצועים טובים יותר כברירת מחדל, בהשוואה לאירועי מגע, שבהם צריך להשתמש במאזינים פסיביים לאירועים כדי להשיג את אותה רמת תגובה.
אפשר למנוע מהדפדפן להשתלט על האירוע באמצעות מאפיין ה-CSS touch-action
. הגדרת הערך none
ברכיב תשבית את כל הפעולות שהוגדרו בדפדפן והופעלו דרך הרכיב הזה. אבל יש מספר ערכים אחרים לצורך שליטה ברמת פירוט גבוהה יותר, כמו pan-x
, שמאפשרים לדפדפן להגיב לתנועה בציר x אבל לא בציר y. ב-Chrome 55 יש תמיכה בערכים הבאים:
auto
|
ברירת מחדל. הדפדפן יכול לבצע כל פעולת ברירת מחדל. |
none
|
הדפדפן לא רשאי לבצע פעולות ברירת מחדל. |
pan-x
|
הדפדפן רשאי לבצע רק את פעולת ברירת המחדל של גלילה אופקית. |
pan-y
|
הדפדפן רשאי לבצע רק את פעולת ברירת המחדל של גלילה אנכית. |
pan-left
|
הדפדפן רשאי לבצע רק את פעולת ברירת המחדל של גלילה אופקית, ורק כדי להזיז את הדף שמאלה. |
pan-right
|
הדפדפן רשאי לבצע רק את פעולת ברירת המחדל של גלילה אופקית, ורק כדי להזיז את הדף ימינה. |
pan-up
|
הדפדפן רשאי לבצע רק את פעולת ברירת המחדל של גלילה אנכית, ורק כדי להזיז את הדף למעלה. |
pan-down
|
הדפדפן רשאי לבצע רק את פעולת ברירת המחדל של גלילה אנכית, ורק כדי להזיז את הדף למטה. |
manipulation
|
הדפדפן רשאי לבצע רק פעולות גלילה ושינוי מרחק התצוגה. |
לכידת מצביע
האם אי פעם הקדשתם שעה מתסכלת לניפוי באגים באירוע mouseup
שבור, עד שהבנתם שהסיבה לכך היא שהמשתמש משחרר את הלחצן מחוץ ליעד הקליק? לא, נכון? אוקיי, אולי זה רק אצלי.
עם זאת, עד עכשיו לא הייתה דרך טובה באמת לטפל בבעיה הזו. כמובן, אפשר להגדיר את הטיפול באירועים של mouseup
במסמך, ולשמור מצב מסוים באפליקציה כדי לעקוב אחרי הדברים. עם זאת, זה לא הפתרון הפשוט ביותר, במיוחד אם אתם מפתחים רכיב אינטרנט ומנסים לשמור על בידוד.
אירועי סמן הם פתרון הרבה יותר טוב: אפשר לתעד את הסמן, כך שבטוח תקבלו את האירוע pointerup
(או כל אחד מחבריו החמקמקים).
const foo = document.querySelector('#foo');
foo.addEventListener('pointerdown', ev => {
console.log('Button down, capturing!');
// Every pointer has an ID, which you can read from the event.
foo.setPointerCapture(ev.pointerId);
});
foo.addEventListener('pointerup',
ev => console.log('Button up. Every time!'));
תמיכה בדפדפנים
נכון למועד כתיבת המאמר, יש תמיכה באירועי סמן (Pointer Events) ב-Internet Explorer 11, Microsoft Edge, Chrome ו-Opera, ותמיכה חלקית ב-Firefox. כאן תוכלו למצוא רשימה מעודכנת.
כדי למלא את הפערים, אפשר להשתמש ב-Pointer Events polyfill. לחלופין, אפשר לבדוק את תמיכת הדפדפן בזמן הריצה:
if (window.PointerEvent) {
// Yay, we can use pointer events!
} else {
// Back to mouse and touch events, I guess.
}
אירועי סמן הם מועמדים מצוינים לשיפור הדרגתי: פשוט משנים את שיטות האי initialization כדי לבצע את הבדיקה שלמעלה, מוסיפים מנהלים של אירועי סמן בבלוק if
ומעבירים את המנהלים של אירועי העכבר/המגע לבלוק else
.
אז כדאי לנסות אותן ולספר לנו מה חשבתם.