İleriye doğru yönlendirme

Sérgio Gomes

Web'deki öğeleri göstermek eskiden basitti. Fareniz vardı, etrafta hareket ettirdiniz, bazen düğmelere bastınız. Fare dışındaki her şey tek bir gibi taklit ediliyor ve geliştiriciler tam olarak neye güvenmeleri gerektiğini biliyorlardı.

Basitlik ise her zaman iyi anlamına gelmez. Zamanla, her şeyin fare olmadığı (veya fare gibi davranmadığı) giderek daha önemli hale geldi: Yaratıcılığınızın son derece serbest olması için basınca duyarlı ve eğilebilir kalemler kullanabilirdiniz. Parmaklarınızı kullanabiliyordunuz. Bu yüzden ihtiyacınız olan tek şey cihaz ve elinizdi. Ayrıca, elinizin altındayken neden birden fazla parmağınız eklemeye ne dersiniz?

Bu konuda bize yardımcı olmak için bir süredir dokunma etkinlikleri kullanıyoruz. Ancak bunlar, özellikle dokunmayla ilgili tamamen ayrı bir API'ler ve hem fare hem dokunmayı desteklemek isterseniz iki ayrı etkinlik modeli kodlamanız gerekiyor. Chrome 55'te, her iki modeli birleştiren daha yeni bir standart mevcuttur: işaretçi etkinlikleri.

Tek etkinlik modeli

İşaretçi etkinlikleri dokunma, kalemler ve fareleri tek bir etkinlik grubunda bir araya getirerek tarayıcının işaretçi giriş modelini birleştirir. Örneğin:

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

Aşağıda tüm mevcut etkinliklerin listesini bulabilirsiniz. Bunlar fare etkinliklerine aşinaysanız size oldukça tanıdık gelecektir:

pointerover İşaretçi, öğenin sınırlayıcı kutusuna girdi. Bu işlem, fareyle üzerine gelme özelliğini destekleyen cihazlarda hemen veya desteklemeyen cihazlarda pointerdown etkinliğinden önce gerçekleşir.
pointerenter pointerover özelliğine benzer ancak alt öğeleri farklı bir şekilde işlemez ve baloncuk olarak işlemez. Spesifikasyonlarla ilgili ayrıntılar.
pointerdown İşaretçi, giriş cihazının semantiğine bağlı olarak bir düğmeye basılarak veya kişi kurularak etkin düğme durumuna girdi.
pointermove İşaretçinin konumu değişti.
pointerup İşaretçi etkin düğme durumundan ayrıldı.
pointercancel Bir hata oluştu. Bu durumda, işaretçinin daha fazla etkinlik gösterme olasılığı düşüktür. Yani devam etmekte olan tüm işlemleri iptal edip nötr giriş durumuna geri dönmeniz gerekir.
pointerout İşaretçi öğenin veya ekranın sınırlayıcı kutusundan ayrıldı. Ayrıca, cihaz fareyle üzerine gelme özelliğini desteklemiyorsa pointerup sonrasında.
pointerleave pointerout özelliğine benzer ancak alt öğeleri farklı bir şekilde işlemez ve baloncuk olarak işlemez. Spesifikasyonlarla ilgili ayrıntılar.
gotpointercapture Öğe, işaretçi yakalama özelliğini aldı.
lostpointercapture Yakalanan işaretçi serbest bırakıldı.

Farklı giriş türleri

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

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 tarayıcılarda, sayfayı kaydırmak, yakınlaştırmak veya yenilemek için belirli hareketler kullanılır. Dokunma etkinlikleri söz konusu olduğunda, bu varsayılan işlemler gerçekleşirken etkinlik almaya devam edersiniz. Örneğin, kullanıcı ekranı kaydırırken touchmove tetiklenmeye devam eder.

İşaretçi etkinlikleri sayesinde, kaydırma veya yakınlaştırma gibi varsayılan bir işlem tetiklendiğinde, tarayıcının işaretçinin kontrolünü ele geçirdiğini bildiren 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ı yanıt verme düzeyine ulaşmak için pasif etkinlik işleyicileri kullanmanız gereken dokunma etkinliklerine kıyasla varsayılan olarak daha iyi performans sağlar.

touch-action CSS özelliğiyle tarayıcının kontrolü ele almasını durdurabilirsiniz. Bir öğede none değerine ayarlanırsa bu öğe üzerinden başlatılan tüm tarayıcı tanımlı işlemler devre dışı bırakılır. Ancak daha ayrıntılı kontroller için pan-x gibi daha ayrıntılı başka değerler de vardır. Bu değerler, tarayıcının y eksenindeki harekete tepkiyi değil, x eksenindeki harekete tepki vermesini sağlar. Chrome 55 aşağıdaki değerleri destekler:

auto Varsayılan; tarayıcı varsayılan herhangi bir işlemi gerçekleştirebilir.
none Tarayıcının varsayılan işlemleri gerçekleştirme izni yok.
pan-x Tarayıcının yalnızca varsayılan yatay kaydırma 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ının yalnızca varsayılan yatay kaydırma işlemini gerçekleştirmesine ve sayfayı sola kaydırmasına izin verilir.
pan-right Tarayıcının yalnızca varsayılan yatay kaydırma işlemini gerçekleştirmesine ve yalnızca sayfayı sağa kaydırmasına izin verilir.
pan-up Tarayıcının yalnızca varsayılan dikey kaydırma işlemini gerçekleştirmesine ve yalnızca sayfayı yukarı kaydırmasına izin verilir.
pan-down Tarayıcının yalnızca varsayılan dikey kaydırma işlemini gerçekleştirmesine ve yalnızca sayfayı aşağı kaydırmasına izin verilir.
manipulation Tarayıcının yalnızca kaydırma ve yakınlaştırma işlemleri yapmasına izin verilir.

İşaretçi yakalama

Hiç bozuk bir mouseup etkinliğinde hata ayıklamak için sinir bozucu bir saat harcadınız mı? Bunun nedeninin, tıklama hedefinizin dışındaki düğmeyi bırakmak olduğunu fark edene kadar? Cevabınız hayır mı? Tamam, belki sadece ben kullanıyorum.

Yine de, bugüne kadar bu sorunla başa çıkmanın gerçekten iyi bir yolu yoktu. Elbette, dokümanda mouseup işleyicisini ayarlayıp uygulamanızda durum kaydedebilir ve işlemleri takip etmek için kullanabilirsiniz. Ancak, özellikle bir web bileşeni oluşturuyor ve her şeyi güzel ve izole tutmaya çalışıyorsanız, en anlaşılır çözüm bu değildir.

İşaretçi etkinlikleri çok daha iyi bir çözüm sunar: İşaretçiyi yakalayarak pointerup etkinliğini (veya diğer zor arkadaşlarından) alabilirsiniz.

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 yazma sırasında İşaretçi Etkinlikleri; Internet Explorer 11, Microsoft Edge, Chrome ve Opera'da, kısmen ise Firefox'ta desteklenmektedir. Güncel listeyi caniuse.com adresinde bulabilirsiniz.

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

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

İşaretçi etkinlikleri, progresif geliştirme için mükemmel bir adaydır: Yukarıdaki kontrolü yapmak için başlatma yöntemlerinizi değiştirin, if bloğuna işaretçi etkinlik işleyiciler ekleyin ve fare/dokunma etkinlik işleyicilerinizi else bloğuna taşıyın.

Haydi, arkadaşlarınızı deneyin ve görüşlerinizi bizimle paylaşın.