React ile sürükleyerek kaydırılan bileşen nasıl yapılır?

React’te yatay bir alanı fareyle sürükleyerek kaydırmayı ve sürükleme sırasında yanlışlıkla tıklamayı önlemeyi anlattım.

React · JavaScript · Frontend

Güncelleme:

Kodlamaya geçmeden önce hangi girdilere ihtiyacımız var onları belirlemeliyiz. Kaydırılabilir bir scroll yapmamız için öncelikle;

  • İki fare konumu arasındaki farkı piksel cinsinden hesaplamak.

  • Sürüklemenin başındaki scroll konumunu saklamak.

Mouse eventında mouse pozisyonumuzun tarayıcının görünüm alanı sınırlarına göre fare konumunun değerlerini (px) vereceğinden clientX ve clientY kullanacağız. Aşağıdaki görselde clientX ve clientY arasındaki fark görünüyor.

CLIENT → The Browser window

clientX clientY = values (px) of the mouse position relative to the Browser’s viewport boundaries.

PAGE → The Whole Document

pageX pageY = values (px) of the mouse position relative to the Document most-top/left “sides”.

SCREEN → Your Screen

screenX and screenY are the values (px) of the current mouse position relative to the physical screen.

Tarayıcıda screen, page ve client koordinatlarının başlangıç noktaları
detaylı resim

Soldaki görselde scrollTop ve scrollLeft bizim scroll pozisyonumuzun mevcut pixel değerlerini veriyor. Kısa bir özetin ardından şimdi biraz karmaşık olan kısma yani pozisyonları hesaplama kısmına bakalım.

İki fare konumu ve başlangıç scroll değeriyle kaydırma hesabı

İlk aşama

İlk önce mousedown eventında clientX, clientY, scrollTop ve scrollLeft değerlerini bir objede tutalım.

mousedown olayında fare konumunu ve scroll değerlerini kaydeden kod
mousedown event

İkinci aşama

İkinci aşamada ise mousemove eventından gelen clientY değerini alalım. Hesaplamalarımızı mousemove üzerinden yapacağız. Çünkü burada mouse’a ön tıkladığımızda ve aşağı doğru sürüklediğimizde scroll konumunu güncellememiz gerekiyor.

mousemove olayında scroll konumunu güncelleyen kod

Mousemove eventımızda biz farenin sol tıkına bastıktan sonra her mouse hareketinde çalışıyor. Buradaki mantık mousedown eventından alınan clientX, clientY değerleri mousemovedaki clientX,clientY değerlerinden çıkarıp bu farkı mousedown eventında aldığımız mevcut scrollTop ve scrollLeft değerlerini çıkarmak.

Sonrasında scrollTop ve scrollLeft ile elementimizin scroll pozisyonlarını güncellemek. Böyle olmasının sebebini aşağıdaki resimde gösteriyorum.

Sürükleme yönü ile scroll konumu arasındaki ilişki

Aslında her şey iki mouse pozisyonunun arasındaki farktan ne kadar pixel pozisyon değiştirmemiz gerektiğini hesaplayıp, bu farkıda scrollToptan çıkartarak pozisyonumuzu güncellememizden ibaret. Buradaki önemli nokta mousedown eventımızda pozisyonların değerlerini kaydetmemiz.

Şimdi bu componentimizin childrenlarında buttonlar vs. olabilir ve sürükleme işlemi yapmak istediğimizde bu butonlara tıklayabiliyoruz malesefki bubbling etkisi oluyor. Bunu çözmek için kısa sürekiğine componentimizin ilk child ögesine pointerEvent özelliğini none yaparak js eventlarına kapatıyoruz ve böylece sorun ortadan kalkıyor

Sürükleme esnasında Componentimizin içerisindeki butonlara tıklamayı engelleme

sadece mousedown işlevimizin içerisinde setTimeout kullanarak

Örnekte 250 milisaniye sonra alt öğelerin pointer olaylarını kapatıyoruz. eğer 250 milisaniyeden önce mouseup eventımız çalışırsa onun içerisinde de clearTimeout ile bu timeoutu sonlandırıyor ve pointereventlarımızı açıyoruz.

Kullanıcının scroll yaparken yazıları seçmesini engellemek için userSelect i none yapıyoruz eventları elementimizi değilde document üzerinden çağırmamızın sebebi mousedown iken mouse umuzu elementimizin dışına çıkardığımızda ve mouseup yaptığımızda sol tıktan parmağımızı çektığımızde ve mouse mizi tekrar elementin üzerine getirdiğimizde hala mousedown eventında kalmasıdır deneyebilirsiniz.

Bunun nedenide aslında elementimizin içerisinde gerçekleşen bir mouseup olay olmadığından görmemesi normal.

Son olarak childrenlarımızı return fonksiyonumuzun içerisine yerleştiriyoruz ve artık bu bileşenin içindeki her şey sürüklenebilir scrolla sahip oldu.

kodların tam hali codesandbox ta ama orada scrollTo eventını çalıştıramadım ne kadar denesemde ama normalde çalışıyor

CodeSandbox örneği

Bu örnek fare olaylarıyla yazılmıştı. Aynı davranışı fare ve dokunma için kuracaksan Pointer Events kullanabilirsin. Dinleyicileri ve zamanlayıcıları bileşen kaldırıldığında temizle. Bir tıklamayı sürükleme olarak saymak için yalnızca süreye bakmak yerine hareket mesafesini de ölç.

Kaynaklar

  1. React useRef dokümantasyonu
  2. MDN Element.scrollLeft

Yazar:

TypeScript, React ve Node.js ile çalışan Full Stack Developer. 2019’dan beri web geliştirme; ürün arayüzleri, API ve analitik deneyimi.

Biraz da benden