İleriye doğru yönlendirme

Sérgio Gomes

Web'de bir nesneyi işaretlemek eskiden basit bir işlemdi. Fareniz vardı, onu hareket ettiriyordunuz, bazen düğmelere basıyordunuz ve bu kadardı. Fare olmayan her şey fare olarak taklit edildi ve geliştiriciler tam olarak neyle karşılaşacaklarını biliyordu.

Basit tasarım demek her zaman iyi tasarım demek değildir. Zamanla, her şeyin fare olmaması (veya öyle davranmaması) giderek daha önemli hale geldi: Basınca duyarlı ve eğime duyarlı kalemler sayesinde inanılmaz bir yaratıcı özgürlük elde edebilirsiniz. Parmaklarınızı kullanabilirsiniz. Böylece, tek ihtiyacınız cihaz ve elinizdir. Ayrıca, neden birden fazla parmak kullanmayasınız?

Bu konuda bize yardımcı olması için bir süredir dokunma etkinlikleri kullanıyoruz. Ancak bunlar, dokunma için tamamen ayrı bir API olduğundan hem fareyi hem de dokunmayı desteklemek istiyorsanız iki ayrı etkinlik modeli kodlamanızı zorunlu kılar. Chrome 55, her iki modeli de birleştiren daha yeni bir standartla birlikte sunulur: işaretçi etkinlikleri.

Tek bir etkinlik modeli

İşaretçi etkinlikleri, tarayıcı için işaretçi giriş modelini birleştirerek dokunma, kalem ve fareleri tek bir etkinlik grubuna getirir. Örneğin:

document.addEventListener('pointermove',
    ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
    ev => console.log('The pointer is now over foo.'));

Kullanılabilir tüm etkinliklerin listesi aşağıda verilmiştir. Fare etkinliklerini biliyorsanız bu listeyi tanıyabilirsiniz:

pointerover İşaretçi, öğenin sınırlayıcı kutusuna girmiştir. Bu işlem, fareyle üzerine gelme özelliğini destekleyen cihazlarda hemen, desteklemeyen cihazlarda ise bir pointerdown etkinliğinden önce gerçekleşir.
pointerenter pointerover ile benzerdir ancak üste çıkmaz ve alt öğeleri farklı şekilde işler. Spesifikasyonla ilgili ayrıntılar.
pointerdown Gösterge, giriş cihazının semantikasına bağlı olarak bir düğmeye basıldığında veya temas kurulduktan sonra etkin düğme durumuna girmiştir.
pointermove İşaretçinin konumu değişti.
pointerup İşaretçi, etkin düğme durumundan çıktı.
pointercancel İşaretçinin başka etkinlik yayınlama olasılığının düşük olduğu anlamına gelen bir durum Bu nedenle, devam eden işlemleri iptal etmeniz ve nötr bir giriş durumuna geri dönmeniz gerekir.
pointerout İşaretçi, öğenin veya ekranın sınırlayıcı kutusunu terk etti. Cihaz fareyle üzerine gelme özelliğini desteklemiyorsa pointerup sonrasında da
pointerleave pointerout ile benzerdir ancak üste çıkmaz ve alt öğeleri farklı şekilde işler. Spesifikasyonla ilgili ayrıntılar.
gotpointercapture Öğe işaretçi yakalama aldı.
lostpointercapture Yakalanan işaretçi serbest bırakıldı.

Farklı giriş türleri

Genel olarak İşaretçi Etkinlikleri, farklı giriş cihazları için ayrı giriş işleyicileri kaydetmenize gerek kalmadan girişten bağımsız bir şekilde kod yazmanıza olanak tanır. Elbette, giriş türleri arasındaki farklara (ör. fareyle üzerine gelme kavramının geçerli olup olmadığı) dikkat etmeniz gerekir. Farklı giriş cihazı türlerini ayırt etmek istiyorsanız (örneğin, farklı girişler için ayrı kod/işlev sağlamak amacıyla) bunu aynı etkinlik işleyicileri içinden PointerEvent arayüzünün pointerType mülkünü kullanarak yapabilirsiniz. Örneğin, bir yan gezinme çekmecesi kodluyorsanız pointermove etkinliğinizde aşağıdaki mantığı kullanabilirsiniz:

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;
}

Varsayılan işlemler

Dokunmatik ekranlı tarayıcılarda sayfayı kaydırmayı, yakınlaştırmayı veya yenilemeyi sağlayan belirli hareketler kullanılır. Dokunma etkinliklerinde, bu varsayılan işlemler gerçekleşirken yine de etkinlikler alırsınız. Örneğin, kullanıcı ekranı kaydırırken touchmove yine tetiklenir.

İşaretçi etkinliklerinde, kaydırma veya yakınlaştırma gibi varsayılan bir işlem tetiklendiğinde tarayıcı imlecin kontrolünü aldığını bildirmek için bir pointercancel etkinliği alırsınız. Örneğin:

document.addEventListener('pointercancel',
    ev => console.log('Go home, the browser is in charge now.'));

Yerleşik hız: Bu model, aynı düzeyde duyarlılığa ulaşmak için etkinlik dinleyicilerini kullanmanız gereken dokunma etkinliklerine kıyasla varsayılan olarak daha iyi performans sağlar.

touch-action CSS mülkü ile tarayıcının kontrolü ele almasını durdurabilirsiniz. Bir öğede none olarak ayarlandığında, söz konusu öğe üzerinde başlatılan tüm tarayıcı tanımlı işlemler devre dışı bırakılır. Ancak daha ayrıntılı kontrol için pan-x gibi başka değerler de vardır. Bu değerler, tarayıcıya y eksenindeki hareketlere değil, x eksenindeki hareketlere tepki vermesini sağlar. Chrome 55 aşağıdaki değerleri destekler:

auto Varsayılan; tarayıcı herhangi bir varsayılan işlemi gerçekleştirebilir.
none Tarayıcının varsayılan işlemler gerçekleştirmesine izin verilmez.
pan-x Tarayıcının yalnızca yatay kaydırma varsayılan işlemini gerçekleştirmesine izin verilir.
pan-y Tarayıcının yalnızca dikey kaydırma varsayılan işlemini gerçekleştirmesine izin verilir.
pan-left Tarayıcı yalnızca yatay kaydırma varsayılan işlemini gerçekleştirebilir ve sayfayı yalnızca sola kaydırabilir.
pan-right Tarayıcının yalnızca yatay kaydırma varsayılan işlemini gerçekleştirmesine ve sayfayı yalnızca sağa kaydırmasına izin verilir.
pan-up Tarayıcıya yalnızca dikey kaydırma varsayılan işlemini gerçekleştirmesine ve yalnızca sayfayı yukarı kaydırmasına izin verilir.
pan-down Tarayıcı yalnızca dikey kaydırma varsayılan işlemini gerçekleştirebilir ve yalnızca sayfayı aşağı kaydırabilir.
manipulation Tarayıcının yalnızca kaydırma ve yakınlaştırma işlemleri yapmasına izin verilir.

İşaretçi yakalama

Kullanıcının düğmeyi tıklama hedefinizin dışında bırakmasından kaynaklandığını fark edene kadar bozuk bir mouseup etkinliğinden saatlerce can sıkıcı bir şekilde hata ayıklama yaptınız mı? Cevabınız hayır mı? Tamam, belki de sadece benim sorunum.

Ancak bu sorunla başa çıkmanın iyi bir yolu yoktu. Elbette, belgede mouseup işleyiciyi ayarlayabilir ve bazı durumları takip etmek için uygulamanızda durum kaydedebilirsiniz. Ancak özellikle bir web bileşeni oluşturuyor ve her şeyi birbirinden ayrı tutmaya çalışıyorsanız bu en temiz çözüm değildir.

İşaretçi etkinlikleri çok daha iyi bir çözüm sunar: İşaretçiyi yakalayabilirsiniz. Böylece, pointerup etkinliğini (veya kaçak arkadaşlarından herhangi birini) yakalayabilirsiniz.

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!'));

Tarayıcı desteği

Bu makalenin yazıldığı sırada İşaretçi Etkinlikleri Internet Explorer 11, Microsoft Edge, Chrome ve Opera'da desteklenmekte, Firefox'ta ise kısmen desteklenmektedir. Güncel listeyi caniuse.com'da bulabilirsiniz.

Boşlukları doldurmak için İşaretçi Etkinlikleri polyfill'ini kullanabilirsiniz. Alternatif olarak, çalışma zamanında tarayıcı desteğini kontrol etmek de kolaydır:

if (window.PointerEvent) {
    // Yay, we can use pointer events!
} else {
    // Back to mouse and touch events, I guess.
}

İşaretçi etkinlikleri, aşamalı geliştirme için mükemmel bir adaydır: Başlatma yöntemlerinizi yukarıdaki kontrolü yapacak şekilde değiştirin, if bloğuna işaretçi etkinliği işleyicileri ekleyin ve fare/dokunma etkinliği işleyicilerinizi else bloğuna taşıyın.

Bu özellikleri deneyip düşüncelerinizi bizimle paylaşın.