VUE.JS

Vue.js Özel Direktifler (Custom Directives)

Güncelleme:
Vue.js direktiflerinden (directives) ve yeteneklerinden daha önce bahsetmiştim. Bu yazıda, var olan direktiflere ek olarak, ihtiyaçlarımız doğrultusunda özelliklere sahip özelleştirilmiş direktifleri (custom directives) nasıl oluşturabileceğimizden ...
GÖRSEL
Vue.js direktiflerinden (directives) ve yeteneklerinden daha önce bahsetmiştim. Bu yazıda, var olan direktiflere ek olarak, ihtiyaçlarımız doğrultusunda özelliklere sahip özelleştirilmiş direktifleri (custom directives) nasıl oluşturabileceğimizden ve bu süreçte nelere dikkat etmemiz gerektiğinden bahsedeceğim.

Vue.js Custom Directives

Vue.js çeşitli işlemler için ön tanımlı olarak v-if, v-model, v-bind, v-on, v-text gibi belirli yeteneklere sahip pek çok direktifi kullanıma hazır olarak bulundurmakta. Ancak, kimi zaman bu yeteneklerden daha fazlasına ihtiyaç duyulduğunda, kimi zaman ise bazı işlemleri daha pratik hale getirmek amacıyla özelleştirmelere ihtiyaç duyulabilmekte. İşte, bu gibi durumlar için Vue bize local ve/ya global olarak kendi direktiflerimizi oluşturma imkanı sunmakta. Hemen basit bir örnekle konuyu detaylandıralım. Mesela, bir input element’ine daha tıklanmadan focus’lanalım ve bunun yanı sıra border stiline de müdahale edelim.
<input type="text" placeholder="Text me!" v-focus />
Vue.directive('focus', {
  inserted: function (el) {
    el.focus();
    el.style.border='thick solid #0000FF';
  }
})
Evet, direktifimizin adı v-focus, ilk parametremiz olan name alanı aynı zamanda direktifin de kendisini tanımlamakta ve v- ön ekini de kullanarak elementlere, component’lere dahil edebilmekteyiz. Oluşturduğumuz v-focus direktifi bir global directive. el ile elemente ulaşabilmemizi ve DOM‘a müdahale edebilmemizi sağlamakta. Aynı direktifi local olarak da oluşturalım.
directives: {
  focus: {
    inserted: function (el) {
      el.focus();
      el.style.border='thick solid #0000FF';
    }
  }
}
Evet, işlemimiz bu kadar. Yeni bir örnek üzerinden özelleştirilmiş direktif oluştururken kullanabileceğimiz hook’lara bakalım.

Custom Directives: Hook Functions

Direktif tanımlarken şu ek hook fonksiyonları da opsiyonel olarak kullanabilmekteyiz.
  • bind, elemente ilk bağlandığında, bir kez çağırılır. Tek seferlik işlemler için bu hook fonksiyonundan faydalanabiliriz.
  • inserted, çağırılan element ana node’una (parent node) eklendiğinde işleme alınır.
  • update, taşıyıcı bileşenin (containing component) VNode’unda değişiklik olduğunda, mümkünse alt/iç component’ten önce çağırılır. Direktifin değeri değişebilir ve/ya değişmeyebilir. Ancak, bind edilen değerlere (current values and old values) göz atılarak gereksiz olduğu düşünülen güncellemeler görmezden gelinebilir.
  • componentUpdated, Taşıyıcı component’in ve/ya alt/iç bileşenlerin VNode’unda değişiklik olduğunda çağırılır.
  • unbind, elementten koparıldığında, bir kez çağırılır
Bind ile hemen bir örnek işlem gerçekleştirelim.
<section id="app" class="section" v-cloak>
      Width: {{ window.width }}, Height: {{ window.height }}
      <hr />
      <h1 class="title is-1" v-wsize:top="[window.width, window.height]">First Level</h1>
      <p class="is-medium">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas vel efficitur ligula, vel lacinia tortor. Fusce
      eu quam arcu. Donec blandit sapien ut diam finibus venenatis. Mauris eget nisl ut diam tincidunt eleifend. Sed ut
      ultrices nibh. Sed quis turpis quis elit vulputate laoreet. Aenean sagittis euismod tortor, non dignissim mauris
      dapibus nec. Etiam est velit, luctus vel luctus ac, sagittis eget odio. In tristique tincidunt nunc id dictum. In
      vitae nisi a odio porttitor interdum. Morbi nec leo felis. Vestibulum dolor neque, luctus eget augue id, molestie
      feugiat magna. Vivamus fermentum lectus vel erat posuere interdum. Aliquam feugiat magna a risus faucibus rhoncus.</p>
      <hr />
      <h2 class="title is-2" v-wsize="[window.width-400]">Second Level</h2>
      <p class="is-medium">Fusce nisl metus, pharetra et mollis sed, iaculis malesuada justo. Etiam aliquam mi vitae nulla aliquet, vitae
      condimentum nisi pulvinar. Aliquam eu imperdiet sapien, pulvinar feugiat nisi.</p>
      <hr />
      <h3 class="title is-3" v-wsize.on="[window.width - window.height]">Third Level</h3>
      <p class="is-medium">Nullam porta orci ut viverra
      blandit. Nulla lorem sem, convallis non tortor sit amet, luctus placerat sapien. Nullam lectus tortor, lacinia
      vitae nisl nec, tempus feugiat nisi. Praesent ac finibus dui.</p>
  </section>
Vue.directive('wsize', {
  bind(el, binding, vnode) {
    const message = 'width: ' + binding.value[0] + ', height: ' + binding.value[1]
    el.addEventListener('click', function () {
      el.style.border='thick solid #0000FF';
      console.log('Binding arg: ' + binding.arg)
      console.log('Binding value: ' + message)
      console.log('Binding modifiers: ' + JSON.stringify(binding.modifiers))
    });
  }
})
 
var app = new Vue({
  el: '#app',
  data:{
      window: {
        width: 0,
        height: 0
    }
  },
  created() {
      window.addEventListener('resize', this.handleResize)
      this.handleResize();
    },
    destroyed() {
      window.removeEventListener('resize', this.handleResize)
    },
    methods: {
      handleResize() {
        this.window.width = window.innerWidth;
        this.window.height = window.innerHeight;
      }
    }
})
Yukarıdaki örnek tarayıcı penceresinin genişlik ve yükseklik değerlerini created() ve handleResize method’u ile alıp data‘ya aktarmakta. Pencere genişliği ve yüksekliği değiştirildiğinde ilgili değerlerin de reaktif bir şekilde güncellendiğini görebilirsiniz. Gelelim custom directive kullanımına. Görüldüğü üzere wsize adında bir global directive oluşturulmuş.
Vue.directive('wsize', {});
Oluşturulan direktive içeriğinde bind hook fonksiyonunu barındırıyor. Hemen araya basit bir örnek ekleyeyim ve ardından ana örnek ile devam edelim.
Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})
el ile elemente ulaşabilir ve DOM‘a müdahale edebiliriz. Bu işlemin tek seferlik işleme alınacağını unutmamalısınız. Ek olarak, bind hook içerisinde bir olay da tanımlı ve el üzerinden ilgili element ile ilişkili bir olay gerçekleştirildiğinde işleme alınmakta.
el.addEventListener('click', function () {});
İlgili tüm işlemleri toparlayacak ve bir arada görüntüleyecek olursak;
bind(el, binding, vnode) {
    const message = 'width: ' + binding.value[0] + ', height: ' + binding.value[1]
    el.addEventListener('click', function () {
      el.style.border='thick solid #0000FF';
      console.log('Binding arg: ' + binding.arg)
      console.log('Binding value: ' + message)
      console.log('Binding modifiers: ' + JSON.stringify(binding.modifiers))
    });
  }
İnternet tarayıcınızın console’u üzerinden başlıkları tıklayarak argümanlar sayesinde bazı değerlere ulaşabiliriz; binding.arg, binding.value, binding.modifiers ve değişiklikleri takip edebiliriz. Peki, bu değerler tam olarak ne ifade etmekteler?

Directive Hook Arguments

Argümanların tamamı ve değinmediğim diye detaylar için Vue.js > Custom Directives > Directive Hook Arguments bölümüne göz atabilirsiniz. Sıklıkla kullanılan bir direktif üzerinden bakalım:
<button v-on:click.prevent="addItem">Item Ekle</button>
Yukarıdaki örnekte, v-on direktifi click argument ve prevent modifier’ına sahiptir. addItem ise direktifin aldığı değerdir. Hemen liste halinde bu alanları açıklayalım.
  • el: Direktifin bağlanacağı element. Doğrudan DOM’u manipüle etmek için kullanılabilir.
  • binding: Bir object tanımıdır ve şu özellikleri (properties) barındırır.
    • name, direktifin adı (v- prefix olmadan tanımlanır, ancak bu prefix ile çağırılır).
    • value, direktife atanan değerdir. Örneğin, v-my-directive="1 + 1" tanımında değer 2 olacaktır.
    • oldValue, update ve componentUpdated kullanımında son atanan değil, bir önceki değerdir. Değer değişikliği olmaksızın kullanılabilir.
    • expression, atanan değeri string olarak alır. Örneğin, v-my-directive="1 + 1" için expression "1 + 1" şeklinde olacaktır.
    • arg, direktife atanan argümandır. Örneğin, v-my-directive:foo için argüman "foo" olacaktır.
    • modifiers, bir object modifier içerebilir. Örneğin, v-my-directive.foo.bar‘nun içerdiği modifier’lar { foo: true, bar: true } olacaktır..
  • vnode, Vue compiler tarafından oluşturulan virtual node’dur.
  • oldVnode, update ve componentUpdated hook’ları ile erişilebilen bir önceki virtual node’dur.
Yukarıdaki örnekte, bir başlığı tıkladığınızda hem başlığın style’ına müdahale edilmekte hem de console.log ile argument.arg, argument.value ve argument.modifiers değerleri yansıtılmaktadır.

Dinamik Argümanlar

Ayrı bir başlık altında eklemekte fayda var. Argümanlar, aynı zamanda dinamik olabilmektedirler; v-directive:argument=[dataproperty]. Yine, yukarıdaki örnekte görüldüğü üzere v-wsize:top="[window.width, window.height]" ile window.width ve window.height değerleri dinamik olarak atanmaktadırlar.

Son Olarak

Evet, Vue.js temel ihtiyaçlar çerçevesinde ön tanımlı olarak oldukça kapsamlı yetenekler barındıran direktiflere sahip. Ancak, Vue bu ön tanımlı direktiflerin yanı sıra, daha pratik ve/ya ihtiyaçlara göre özelleştirilmiş yetenekler barındırmasını istediğimiz direktifler için de özelleştirilmiş tanımlar yapma imkanı sunmakta.
Ceyhun Enki Aksan

Kullanıcı Davranışları Analizi (User Behavior Analysis) ve Kullanıcı Deneyim Tasarımı (UX Design) üzerine çalışmalar yürütmekte, bu süreçte edindiğim teknik ve pratik bilgileri fayda sağlamak motivasyonuyla (afaik / as far as i know) paylaşmaktayım.

HABERDAR OL

Yeni eklenen projeler, eğitimler, içerikler ve yayınlanan videolar e-posta adresine gelsin.