VUE.JS

Vue.js Bileşenler (Components)

Yayın:
Bir web sitesi ya da uygulama pek çok parçadan oluşmakta. Kabaca tarif etmek gerekirse, header, nav, footer ve sidebar genellikle içerik alanı dışında kullandığımız diğer ...
GÖRSEL
Bir web sitesi ya da uygulama pek çok parçadan oluşmakta. Kabaca tarif etmek gerekirse, header, nav, footer ve sidebar genellikle içerik alanı dışında kullandığımız diğer parçalardır diyebiliriz. Ayrıca, çoğu zaman bu yapılar da daha alt parçaların bir araya gelmesiyle oluşmaktadırlar. Header alanı top bar ve search formu içerebilir, footer sayfa bağlantıları ve infodan oluşabilir, sidebar yazı önerileri gibi içerikleri kapsayabilir.
<header>
  <topbar-item v-for="item in topItems"></topbar-item>
</header>
<main>
  <blogpost v-for="post in blogPosts"></blogpost>
</main>
<aside>
  <sidebar-item v-for="item in sideItems"></sidebar-item>
</aside>
<footer></footer>
Elbette bu detaylar uygulamanın ve/ya web sayfasının amacına uygun olarak, ihtiyaçlar çerçevesinde pek çok şekilde ele alınabilir. Parçalardan oluşan, kendi içinde bir bütünlük oluşturan bu yapının kolay yapılandırılabilir olması bir avantaj sağlamaktadır. Bu sayede, benzer yapıları tekrar tekrar kullanabilir, daha az kodla daha fazla işlem gerçekleştirerek performans sağlayabiliriz. Template sistemleri ile ilgili yazıda da bahsettiğim üzere bu amaca yönelik farklı noktalara odaklanan pek çok çözüm yolu mevcut. Vue.js bu süreci (Angular ve React ile benzer şekilde) bileşenlerle (components) yönetmeyi mümkün kılmakta.

Vue.js Bileşenler (Components)

Yukarıdaki örnek bileşen yapısına tekrar bir göz atalım. Basitleştirilmiş şekilde paylaştığım bu örnek gibi, web sitenizi ve/ya uygulamanızı tasarlamaya / kodlamaya başladığınızda yapıların da netleştiğini görecek ve hatta çok daha alt bileşenler oluşturmaya çalışacaksınız. Vue.js tüm bu ihtiyaçlara cevap olarak birkaç farklı şekilde bileşenler oluşturmamızı sağlar. Aşağıda bu farkılıklara dair açıklamalar ve basitten karmaşığa doğru bileşenler oluşturmaya dair örnekler paylaşmaya çalışacağım. Bu yapıların bir kural değil, ihtiyaçlar çerçevesinde ortaya çıkan çözümler olduğunu unutmayın. Bu nedenle, web sayfası ve/ya uygulamanın kullanımını göz önünde bulundurarak kendi bileşenlerinizi oluşturmaya çalışın.

Oldukça basit bir örnekle başlayalım:

<div id="app">
    <div v-cloak>
      <h1>{{ message }}</h1>
      <who></who>
    </div>
  </div>
var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello World!',
      },
      components: {
        who: {
          template: `
          <div>
            <p>Edgar Allan Poe</p>
            <p>Born: January 19, 1809</p>
            <p>Died‎: ‎October 7, 1849</p>
          </div>`
        }
      }
    });
Aynı işlemi şu şekilde de gerçekleştirebiliriz:
    const About = {
      template: `
    <div>
      <p>Edgar Allan Poe</p>
      <p>Born: January 19, 1809</p>
      <p>Died‎: ‎October 7, 1849</p>
    </div>`
    }
 
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello World!',
      },
      components: {
        who: About
      }
    });

Bu örnekte bizim için 2 önemli nokta var. İlki #app içeriğinde yer alan <who></who>, diğeri de Vue instance içeriğindeki components nesnesi. Aslında, iki alanın da ilişkili olduğu aşikar. Bu basit örnek üzerinden Vue bileşenlerinin (components) nasıl çalıştığına bir bakalım.

Yazının giriş bölümünde, Vue component oluşturmak için (component registration) birden fazla yöntem olduğundan bahsetmiştim. Yukarıdaki yöntem bunlardan biri ve en temel olanı diyebiliriz. Tıpkı bir computed prop, method gibi bir components nesnesi altında istediğimiz sayıda component oluşturabilmekteyiz. Who olarak ifade edilmiş olan component bunlardan biri ve örneğimiz içerisindeki who etiketini ifade etmekte. Görüldüğü üzere component tanımı aynı zamanda etiket olarak kullanılmakta ve içeri template olarak tanımlanan ne ise o şekilde oluşturulmakta. Template tanımında yer alan div bir root element ve p etiketlerini kapsamakta. Bileşen işlemlerinde tıpkı normal instance tanımlamalarında olduğu gibi bir ana kapsayıcı kullanma zorunluluğu söz konusu. İlgili div etiketini kaldırdığınızda ya da yazmayı unuttuğunuzda, Component template should contain exactly one root element. uyarısını alma nedeniniz de bu olacaktır. Şimdi de bir diğer component tanımlamasına geçelim.

Vue.component('person', {
      template: `
      <div>
        <p>Edgar Allan Poe</p>
        <p>Born: January 19, 1809</p>
        <p>Died‎: ‎October 7, 1849</p>
      </div>`
    });
 
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello World!',
      }
    });

Bileşen tanımlamamızı bu defa Vue.component('person', { template: '...' }); şeklinde yaptık ve bileşen adımızı person olarak belirledik. Görüldüğü üzere tanımlanış biçimi dışında kurallarımız aynı. Unutmadan, az önceki örnek ile birlikte 2 biçimi de beraber kullanmak mümkün.

Şimdi, örneklere kısa bir ara verip yerel (local) ve evrensel (global) bileşenlerden bahsetmek istiyorum.

Global Component Registration

Bir bileşen (component) evrensel (global) olarak tanımlandığında herhangi bir root Vue instance içerisinde rahatlıkla kullanılabilirler.
Vue.component('name-1', { /* ... */ })
Vue.component('name-2', { /* ... */ })
Vue.component('name-3', { /* ... */ })
 
new Vue({ el: '#app' })

Unutmadan, yukarıdaki örnek bileşen içeriklerinde yer alan name her bileşen için özel ve ayrıştırıcı olmalıdır. Ad tanımlarken kebab-case ve/ya PascalCase kullanılabilir. Bileşen adı, bir bileşenin aldığı ilk argüman olma özelliğine sahiptir.

Tekrar yukarıdaki global compotent registration örneğine dönecek olursak, ilgili tanımlamaları aşağıdaki şekilde kullanabiliriz.

<div id="app">
  <name-1></name-1>
  <name-2></name-2>
  <name-3></name-3>
</div>
ya da
<div id="app">
  <component is="name-1"></component>
  <component is="name-2"></component>
  <component is="name-3"></component>
</div>
Görüldüğü üzere tek bir root Vue instance’imiz var (#app) ve bileşenlerimizin hepsi bu kapsayıcı (wrapper) içerisinde kullanılmaktalar. Aynı şekilde, dilersek oluşturduğumuz bu bileşenleri birbirlerinin alt bileşenleri olarak da kullanabiliriz.

Local Component Registration

Global component registration dışında bazı gereksinimler söz konusu olabilir. Örneğin, webpack gibi bir derleme sistemi (build system) kullanmak gerektiğinde tüm bileşenler evrensel olarak kaydedilecektir. Bu bileşenlerden bazılarını kullanmayı bıraksak bile son derlemenize yine de dahil edileceklerdir. Bu, gereksiz yük ve performans sorunu anlamına gelmektedir. Çözüm olarak bileşenler JavaScript nesneleri (objects) olarak oluşturulabilirler ve kullanılacak olan bileşen components option olarak instance’a dahil edilebilir.
var name1 = { /* ... */ }
var name2 = { /* ... */ }
var name3 = { /* ... */ }
new Vue({
  el: '#app',
  components: {
    'name-1': name1,
    'name-2': name2
  }
})

Unutmadan, yerel (local) olarak oluşturulan bileşenler alt bileşen (subcomponent) olarak kullanılamazlar ve ilgili bileşen içeriğinde yeniden oluşturulmaları gerekir.

Babel ve Webpack gibi ES2015+ modülleri kullanılıyor ise bileşen tanımları şu şekildedir:

require name1 from './name1.vue'
import name2 from './name2.vue'
 
export default {
  components: {
    // 'name-1': name1
    name1,
    name2
  },
  // ...
}

Evet, component registration sonrasında örneklere ve bileşen özelliklerine kaldığımız yerden devam edebiliriz.

Çoklu Bileşen Kullanımı

Yazıdaki ilk örneğimizi biraz eklemeler yaparak ve global olarak yeniden ele alalım.
<div id="app">
    <div v-cloak>
      <h1>{{ message }}</h1>
      <person></person>
      <person></person>
      <person></person>
    </div>
  </div>
Vue.component('person', {
      template: `
      <div>
        <p>Edgar Allan Poe</p>
        <p>Born: January 19, 1809</p>
        <p>Died‎: ‎October 7, 1849</p>
      </div>`
    });
 
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello World!'
      }
    });
Görüldüğü üzere person etiketini pek çok kez kullanabilmekteyiz. Buradaki sorun her kullanımda bize template içerisinde yer alan aynı değerleri de getiriyor oluşu. Bu gibi durumlar için sıklıkla component props kullanacağız. Ancak, öncesinde örneği biraz değiştireceğim.
<div id="app">
    <div v-cloak>
      <h1>{{ message }}</h1>
      <author-detail v-for="(author, index) in authors" :key="index" :author="author"></author-detail>
    </div>
  </div>

Öncelikle HTML alanımızı oluşturalım. author-detail olarak bir bileşen oluşturmak istiyorum. Bu bileşenin içerisinde birden fazla yazar bilgisi mevcut olacak. Dolayısıyla bileşenin bu yazarları tanımladığım bilgilerle birlikte listelemesini istiyorum.

Bu işlem için oluşturacağım template‘i instance içeriğinde değil, harici bir script tanımı içerisinde oluşturmak istiyorum.

<script type="text/x-template" id="authorIndex">
    <div>
      <p>Name: {{author.name}}</p>
      <p>Born: {{author.born}}</p>
      <p>Died: {{author.died}}</p>
      <hr />
    </div>
  </script>

Esasında template item’i içerisinde tanımlamaktan hiçbir farkı yok. Sadece alternatif bir kullanım örneği olmasını istedim. Kritik nokta template item’ına bu script’in id değerini vermemizin gerektiği. Yazar bilgilerimiz ile birlikte instance şu şekilde olacaktır.

Vue.component('author-detail', {
      props: ['author'],
      template: '#authorIndex',
    });
 
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Favorite Authors',
 
        authors: [{
            name: 'Edgar Allan Poe',
            born: 'January 19, 1809',
            died: 'October 7, 1849'
          },
          {
            name: 'Franz Kafka',
            born: 'July 3, 1883',
            died: 'June 3, 1924'
          },
          {
            name: 'Emil M. Cioran',
            born: 'April 8, 1911',
            died: 'June 20, 1995'
          }
        ]
      }
    });
Diğer bileşen tanımlamamızı da hatırlatmakta fayda var. Aynı bileşen tanımını şu şekilde de yapabilirdik:
      data: {
        / ... /
      },
      components: {
        'author-detail': {
          props: ['author'],
          template: '#authorIndex',
        }
      }

Evet, örnekte yer alan props ile v-for direktifi kullanarak authors içeriğindeki yazarları sırasıyla listeledik. Props ile ilgili detaylardan ve bileşenlerin nasıl birbirleriyle haberleşebileceğinden ayrı bir yazıda bahsedeceğim.

Şimdilik her şey yolunda görünüyor. Lakin, eklemek istediğim bir konu var. Instance içerisinde hep data object olarak tanımlı. Fakat, global component registration aşamasında component kendi data yapısına sahip olduğunda data’nın bir function olması gerekiyor. Bunun nedeni, object olması durumunda root Vue instance ile ilişkili kalacağı ve kendi içeriğini yansıtamayacağı. Bu durumda, function tanımı yapmadığınızda hata ile durumdan haberdar edilirsiniz. Elbette bunu kasıtlı olarak istemiyorsak -ki çoğu zaman istemeyeceğiz- tanımlamamızı şu şekilde yapmamız gerekir:

Vue.component('name1', {
  data: function () {
    return {
      /.../
    }
  },
  template: '...'
})
Son bir örnek yapalım.
<div id="app">
    <div v-cloak>
      <h1>{{ message }}</h1>
      <button-counter></button-counter>
      <button-counter></button-counter>
      <button-counter></button-counter>
      <button-counter></button-counter>
    </div>
  </div>
Vue.component('button-counter', {
      data: function () {
        return {
          count: 0
        }
      },
      methods: {
        addCount() {
          return this.count++
        }
      },
      template: '<button v-on:click="addCount()">You clicked me {{ count }} times.</button>'
    })
 
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Favorite Authors',
      }
    });
Son örnekle bileşen (component) başlangıç yazısını tamamlamış olduk. Bir sonraki yazıda props ile ilgili daha detaylı bilgi aktarmaya çalışacağım.

HABERDAR OL

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