Vue.js ile Drop-Down Component Yapımı

Onur Aslan
7 min readSep 27, 2019

Yön tuşları ile içerisinde ki listede seçim yapabileceğimiz, açılır kapanır bir menu component’i yapımı.

Giriş

Merhaba, öncelikle belirtmek isterim ki bu benim uzun zaman sonra yazdığım ilk içerik. Tekrar yazıyor olmak güzel bir duyguymuş. Umarım faydalı bir içerik olur. :)

Bu belgede Vue.js ile Front-End çalışmalarında çok sık (ve işlevsel olarak eksik) kullanılan bir UI ögesini component şeklinde geliştireceğiz. Gözlemlediğim kadarıyla bir çok web sitesinde bu tarz yapılarda yön tuşları ile seçim yapılamamakta. Bu da her seferinde elimiz klavyede iken seçim yapmak için mouse kullanmamızı zorunlu kılan bir eksikliğe yol açıyor.

Bu belgede böyle bir yapıyı component haline getirerek geliştirme yaptığımız uygulamada kolayca bu yapıyı bu tarz araçlara uygulamak amaçlanmıştır.

Ön Koşullar

JavaScript, Vue.js, Html, Css gibi teknolojiler hakkında temel seviyenin üstünde bir bilgi birikimine sahip olmanız bu belgeyi daha kolay anlamanızı sağlayacaktır.

Yapılacaklar

  1. Menu düğmesine tıklandığı zaman kapsayıcı ögenin (menu düğmesinin) hemen altında açılan bir alan (window) yapılacak.
  2. Bu alan, kapsayıcı (parent) yapı içerisinden props olarak geçirdiğimiz bir Array yapısını kendi içinde liste olarak kullanacak.
  3. Kullanıcı, bu alan dışında mouse ile herhangi bir alana tıklarsa bu açılan alan kapanacak.
  4. Bu listede seçim elle ya da klavyeden yön tuşları ile yapılabilecek. Aşağı ve yukarı yön tuşları ile listede gezebilirken, enter tuşu ile bu seçimi seçebileceğiz.
  5. Seçilen bu öge, kapsayıcı yapıya aktarılabilecek.

Başlangıç

Öncelikle bir Vue.js uygulaması oluşturmalıyız. Zaten halihazırda bir Vue uygulamanız var ise direkt component yapımına geçebilirsiniz.

Bu belgede Vue CLI yardımıyla Vue uygulaması oluşturdum. Sizde hızlıca yeni bir tane Vue uygulaması oluşturmak için kullanabilirsiniz. Bu kısım hakkında bir çok kaynak mevcut ve ben bu konuda detay vermeyeceğim, bu bilgileri ön koşullar bölümünde bildiğinizi varsaydım.

vue create vue-dropdown

Component Oluşturma

Uygulamanızın dizin yapısında kullanmış olduğunuz component kısmında yeni bir tane component oluşturalım ve bu component’i kullanacağımız sayfaya dahil edelim.

Ben aşağıda ki görselde görünen şekilde bir component oluşturdum ve direkt app.vue içerisinde kullandım.

app.vue ve vue-dropdown.vue dosyaları

Menu Düğmesi

Drop-down penceresinin açılması için tetiklenmesi gerekmektedir. Bunun içinde bir button oluşturalım. Bu button’a tıklandığı zaman drop-down penceresi açılacak.

App.vue state’i içeresinde ki isMenu değişkeni ile drop-down component’i v-if direktifi ile görünür/gizlenir yapılır.

Drop-Down Penceresi

Bu basit yapıya birazcık stil ekleyerek drop-down penceremizi şekillendirelim. Burada kapsayıcı element (container) için CSS’de “position: relative ”değerini vererek üzerine gelecek olan “position: absolute” bir elementin (drop-down penceresinin) buna göre konumlandırılmasını sağlayacağız. Böylece drop-down component’i görünür olduğunda kapsayıcı elementinin içerisinde konumlandırılmaya başlayacak.

Props

Tasarıma devam etmek için bu drop-down penceresi içinde kullanabileceğimiz liste ögelerine ihtiyacımız olacak. Bunun için kapsayıcı yapıdan component’imize menu listesinde kullanabileceği bir Array geçirmemiz gerekmektedir.

Burada ana yapıdan component’e props Array göndererek drop-down penceresi içerisinde listeledik.

Görüldüğü üzere drop-down penceresinde ki ögeler bitişik. Bunun için gerekli stil düzenlemeleri aşağıda ki görselde ki gibi yapıldı. Ayrıca Bu ögelerin üzerine gelince “hover” için bir stil eklendi.

Click Event

Kullanıcımız eğer drop-down dışında ki bir alana tıklarsa drop-down penceremizin kapanması gerekmektedir. Bunun için component’imiz içerisinde document ögemize bir event/click koymamız gerekmektedir. Daha sonra buradan kullanıcının hangi hedefe tıkladığını kontrol edeceğiz.

İlk olarak component’imizde ana ögeye bir ref=* değeri veriyoruz ki buna daha sonra kolayca bu değerden ulaşabilelim.

Daha sonra component’imizde beforeMount() ve beforeDestroy() kısımlarında “click” için bir event eklememiz gerekmektedir.

Unutmayın beforeDestroy()’da bu event’i silmezseniz router ile geçeceğiniz sayfalarda bu event çalıştırılabilir ve istenmeyen sonuçlar alabilirsiniz.

Burada kullanıcının her bir “click” olayını documentClick fonksiyonuna iletiyoruz.

Bu fonksiyonda ref=* değeri verdiğimiz elementi ve event’den gelen data’yı karşılaştırıyoruz. Eğer bu ikisi birbirine eşit değil ve tıklanan alan drop-down alanı dışındaysa, kullanıcının drop-down aracından çıkmak istediği sonucuna varabiliriz.

Bu fonksiyonun içerisinden component’in bulunduğu ana yapıya bu drop-down penceresinin kapatılmak istendiğini iletmemiz gerekmektedir. Bunun için $emit kullanarak bu istek iletilir.

Benzer bir şekilde bir yol izleyerek listeden mouse ile bir öge seçmesini istersek;

Yukarıda ki görselde vurguladığım şekilde component’imizde “click” ve “$emit” ile seçilen ögeyi ( item’ı ) bir üst yapıya gönderiyoruz. Ana yapıda component’imizin bulunduğu satırda “$emit” ile yolladığımız “key” yardımıyla “@change” tetikleniyor ve gelen veriyi işliyoruz.

Böylece artık açılır-kapanır bir menumüz var ve bu menuden herhangi bir ögeye tıkladığımızda bir üst yapıdan bu veriye erişebiliyoruz.

Yön Tuşları ile Seçim Yapmak

Bu tarz yapılarda her ne kadar mouse ile iş görülse de, tekrar eden form ögelerinde autofocus, dropdown, özel selectbox gibi yapılarda klavyeden listede ki ögeler arasında dolaşmak ve bunlardan birini seçmek UX açısından kullanıcıya güzel bir deneyim yaşatmaktadır.

İzlenilecek yol:

Hangi ögede olduğumuzu anlamak için bir genel index değişkeni (currentIndex) tutmamız gerekmektedir. Klavye ile yön tuşlarından aşağıya ya da yukarıya gitmek istenilirse bu index değerini 1 arttıracağız ya da 1 azaltacağız.

Event ekleyerek klavyeden aşağı, yukarı ve enter tuşlarında ki olayları yakalayacağız.

Drop-down component’imizin state değişkenlerine currentIndex isminde bir değişken ekliyoruz. -1 değerinde olmasının sebebi drop-down penceresi açıldığında ön tanımlı bir seçimin olmamsı için.

vue-dropdown.vue

Daha sonra beforeMount() ve beforeDestroy() kısımlarına “keydown” event’i ekleyeceğiz. Ve son hali aşağıda ki gibi olacak.

vue-dropdown.vue

Kullanıcımız klavyeden bir tuşa bastığında bunu bu event ile yakalayıp captureKey() fonksiyonuna iletmiş olduk.

Bu fonksiyon içerisine ArrowUp, ArrowDown ve enter tuşlarına basıldığında çalışmasını istediğimiz fonksiyonları ekleyeceğiz.

vue-dropdow.vue

Yukarıda ki görselde, ArrowDown ve ArrowUp tuşlarına tıklandığında step() fonksiyonuna aşağı yönde ise 1 yukarı yönde ise -1 değeri gönderirken enter tuşuna basıldığında ise bu seçili ögeyi bir üst yapıya aktaracağız ve drop-down penceresini kapatacağız. Burada select(e) ile enter tuşuna tıklandığı zaman submit olayını pasifleştirmek için e.preventDefault()’dan faydalanacağız.

Ayrıca seçili olan ögeyi drop-down penceresinde öne çıkartmak için CSS içeriğine “.active” adında bir class seçicisi eklemeliyiz. Ve bu class ismini drop-down component’inde ki “v-for” satrına ekleyeceğiz.

vue-dropdown.vue

HTML kısmında da aşağıda ki şekilde aktif olan ögeyi ayırt etmek için currentIndex ve “v-for” dan gelen index’i karşılaştıracağız. Eğer eşitlik söz konusu ise seçili olan ögeye ‘.active’ class’ını ekleyeceğiz. Ayrıca daha sonra kullanmak için bu ögeye bir id değeri veriyoruz.

vue-dropdown.vue

Bu kısımları hazırladıktan sonra step() ve select() fonksiyonlarımızı kodlayabiliriz.

step() fonksiyonunda minimum bir index değeri ile maksimum index değeri belirleyeceğiz. Minimum değere 0 verebiliriz. Böylece arrow keys ile kullanıcı dolaşırken ilk başta ki ögeden aşağı bir index’e inemeyecek.

Aynı şekilde maksimum bir index değeri (listede ki toplam öge sayısı) ile de arrow keys ile kullanıcı en son ögeden sonra bir sonra ki ‘olmayan’ ögenin index’ine geçiş yapamayacak.

vue-dropdown.vue

Burada ki step() fonksiyonunda min ve max index değerlerini belirledik. currentIndex değerini step fonksiyonu parametresinden gelen değer ile direkt topladık. Bu değer 1 veya -1 idi. Daha sonra currentIndex’in değerini max ve min index değerleri ile karşılaştırdık ve currentIndex’i bu sınır değerlerine eşitledik. Böylece currentIndex max değerinde iken yön tuşlarından aşağı tuşuna basılırsa currentIndex, 0 olacaktır, yani listenin ilk ögesine geçecektir. Aynı şekilde currentIndex, 0 ise ve step parametresi -1 ise (yani yukarı tuşuna basılmış) currentIndex -1 olamayacağından bu değer listenin son ögesinin index’ine eşitleniyor, yani max index değerine. Böylece kullanıcı liste içerisinde dolaşabiliyor.

scrollView() fonksiyonu ile her klavyeden tuşa basıldığında drop-down penceresinde ki öge eğer görüntülen alan dışında kalıyorsa otomatik olarak bu ögeye scroll yapılmasını sağlayarak ögenin sürekli görünürde kalmasını sağlıyoruz.

Daha sonra enter tuşu ile bu seçilen ögeyi bir üst yapıya aktaracağız. Burda daha önceden oluşturmuş olduğumuz “$emit(‘change’)” ile array ögesinden şuan ki seçili olan ögenin index’i ile o ögeyi ana yapıya gönderiyoruz.

Artık tüm özellikler ile çalışan bir component’imiz var. Arrow keys ile navigation özelliğini bu component ile tüm açılır-kapanır yapılarda aşağıda ki kod parçacığı şeklinde kullanabileceğiz.

Neler Yapılabilir?

Bu component ile birlikte bir menu düğmesi yerine bir input kullanılabilir. Hatta biraz daha ileriye giderek bu input’da yazan metni props olarak bu component’e aktararak basit bir filtreleme ile “autocomplete” yapabilirsiniz. Ya da bu component’e belirli bir “type” props’u göndererek çeşitli UI element’lerini listede seçilebilir yapabilirsiniz.

Örnek olarak çalışmış olduğum patron.ai şirketinde bu yapı ile drop-down içine bir checkbox listesi koymuştum. Bu yapıyı çeşitli amaçlarda kullanabilirsiniz.

Github

Projenin Github sayfasına bakarak kodlara doğrudan erişebilirsiniz. Umarım faydalı bir içerik olmuştur. Hoşçakalın! :)

Kaynak Kodlar: https://github.com/aslanon/vue-dropdown

Demo: https://aslanon.github.io/vue-dropdown/

--

--