Neler yeni

Foruma hoş geldin 👋, Ziyaretçi

Forum içeriğine ve tüm hizmetlerimize erişim sağlamak için foruma kayıt olmalı ya da giriş yapmalısınız. Foruma üye olmak tamamen ücretsizdir.

  • Merhaba Değerli Ziyaretçimiz, ForumaGel ailesi seni bekliyor! 🌟 Aramıza katılarak güçlü ve samimi topluluğumuzun bir parçası olabilirsin. Burada her üye değerli, her katkı kıymetli. Şimdi üye ol, bizimle birlikte gelişmenin ve keyifli sohbetlerin tadını çıkar! Sevgi ve Saygılarla, ForumaGel Yönetimi ❤️
Yan Yana Banner
Yan Yana Banner
Katılım
7 Nis 2025
Konular
367
Mesajlar
780
Çözümler
1
Tepkime puanı
121
Puan
93
Konum
İstanbul
Web sitesi
forumagel.com
Hazır Kod Bankası - Konu 28: Vue.js Bileşenleri (Components) ve Veri İletişimi




Hazır Kod Bankası Serimizin Yirmi Sekizinci Konusu: Vue.js Bileşenleri ve Veri İletişimi!

Merhaba arkadaşlar! Vue.js'e giriş yaparak (JavaScript Frontend Frameworklerine Giriş (Vue.js Temelleri)), temel veri bağlama, şartlı gösterme ve liste render etme gibi konuları gördük. Artık reaktif web arayüzleri oluşturabiliyoruz. Ancak karmaşık ve büyük web uygulamaları geliştirmeye başladığımızda, tüm HTML şablonunu ve JavaScript mantığını tek bir Vue uygulaması objesi içinde yönetmek hızla zorlaşır. Aynı arayüz parçasını (örneğin bir buton, bir ürün kartı, bir yorum kutusu) birden fazla yerde kullanma ihtiyacı doğar.

İşte burada Bileşenler (Components) kavramı devreye girer. Bileşenler, kendi şablonu (template), JavaScript mantığı (script) ve isteğe bağlı olarak kendi stili (style) olan, bağımsız, yeniden kullanılabilir kullanıcı arayüzü parçalarıdır. Bir web sayfasını veya uygulamasını, tıpkı Legolar gibi, yan yana veya iç içe geçmiş birçok küçük bileşenin birleşimi olarak düşünebilirsiniz.

Bu konuda Vue.js'te bileşenlerin nasıl tanımlandığını ve ana Vue uygulamasında nasıl kullanıldığını öğreneceğiz. En önemlisi, farklı bileşenler arasında veri ve olayların (event) nasıl iletildiğini, özellikle Props (ebeveynden çocuğa veri gönderme) ve Emit (çocuktan ebeveyne olay/veri gönderme) yöntemleriyle detaylı olarak göreceğiz.

Ön Gereksinim: Vue.js Temelleri (JavaScript Frontend Frameworklerine Giriş (Vue.js Temelleri)) anlaşılmış olmalı.

2. Bileşen (Component) Nedir? Neden Kullanılır?[/B]

  • Yeniden Kullanılabilirlik: Bir bileşeni bir kere yazar, uygulamanın farklı yerlerinde tekrar tekrar kullanırsınız. (DRY prensibi: Don't Repeat Yourself).
  • Yönetilebilirlik: Büyük bir UI'ı küçük, odaklanmış parçalara bölerek kodun okunmasını ve bakımını kolaylaştırır.
  • Kod Organizasyonu: HTML, JavaScript ve CSS'i ilgili bileşen etrafında gruplar.
  • Soyutlama: Bileşenin iç detaylarını dışarıdan gizleyerek sadece gerekli arayüzü sunar.
Bir bileşen, aslında Vue tarafından genişletilmiş özel bir HTML elementi gibi davranır.

3. Temel Bileşen Tanımlama ve Kullanma (Global Kayıt)[/B]

Bir bileşeni tanımlamak için Vue.js'in sunduğu seçenekler objesini kullanırız (tıpkı ana Vue uygulaması gibi). Bu seçenekler objesi içinde bileşenin kendi `template`, `data`, `methods`, `props` gibi özelliklerini belirleriz.

Basit bileşenleri (özellikle öğrenme aşamasında veya küçük denemelerde) ana Vue uygulaması objesi üzerinde `component()` metodu ile global olarak kaydedebiliriz. Global olarak kaydedilen bileşenler, uygulamanın herhangi bir yerindeki şablonda doğrudan isimleriyle kullanılabilir.

JavaScript:
    const app = Vue.createApp({
        // Ana uygulama data ve metotları buraya gelir...
        data() {
            return {
                anaMesaj: 'Ana Uygulama Mesajı',
                anaSayac: 0
            }
        }
        // ...
    });

    // Yeni bir 'merhaba-mesaj' bileşeni tanımlama ve global olarak kaydetme
    app.component('merhaba-mesaj', { // Bileşen adı (kebab-case önerilir)

        // Bileşenin kendi HTML şablonu
        template: '<div><p>{{ mesaj }}</p><button @click="sayaciArtir">Bileşen Sayacını Artır</button><p>Bileşen Sayacı: {{ sayac }}</p></div>',

        // Bileşenin kendi reaktif verisi (bir fonksiyon dönmeli!)
        data() {
            return {
                mesaj: 'Merhaba Bileşen!',
                sayac: 0 // Bu sayaç sadece bu bileşene aittir
            }
        },

        // Bileşenin kendi metotları
        methods: {
            sayaciArtir() {
                this.sayac++;
            }
        }
    });

    // Vue uygulamasını #app elementine bağla
    app.mount('#app');
Şimdi bu bileşeni ana HTML şablonunda kullanabiliriz:

HTML:
<div id="app">
    <h1>Ana Uygulama</h1>
    <p>{{ anaMesaj }}</p> {# Ana uygulama data'sından #}

    <hr>

    <h2>Bileşen Kullanımı</h2>
    {# Tanımladığımız 'merhaba-mesaj' bileşenini kullan #}
    <merhaba-mesaj></merhaba-mesaj> {# Bileşen buraya render edilecek #}

    <merhaba-mesaj></merhaba-mesaj> {# Aynı bileşeni tekrar kullan! Kendi data ve sayacı olacak #}

</div>
{# Yukarıdaki Vue JS kodunun bu HTML dosyasında script etiketleri içinde olduğunu varsayın #}
Açıklama: `app.component()` ile `merhaba-mesaj` bileşenini kaydettik. Bu bileşenin kendi `template`, `data` ve `methods`'i var. `<merhaba-mesaj></merhaba-mesaj>` etiketi kullanıldığında Vue, o etiketi bileşenin şablonuyla değiştirir ve her kullanımda bileşenin `data`'sının yeni bir kopyasını oluşturur. İki `<merhaba-mesaj>` örneğinin kendi sayaçları olacaktır, birbirlerinden bağımsızdırlar.

4. Props İle Veri Gönderme (Parent -> Child)[/B]

Bir bileşen genellikle ebeveyninden (parent) veri alarak davranır. Örneğin bir `UrunKarti` bileşeni, hangi ürün bilgilerini göstereceğini ebeveyninden almalıdır. Ebeveynden çocuğa veri göndermenin temel yolu Props (Özellikler)'tir. Props, ebeveynin bileşene bağladığı özel niteliklerdir ve çocuk bileşen bu değerleri kendi içinde kullanabilir. Propslar, çocuk bileşen içinde değiştirilmemelidir (tek yönlü veri akışı).

Çocuk Bileşende Props Tanımlama: Çocuk bileşenin seçenekler objesine `props` adında bir obje eklenir. Bu objede beklenen prop isimleri belirtilir.

JavaScript:
    // Ürün Kartı bileşeni
    app.component('urun-karti', {
        // Bu bileşenin beklediği verileri (props) tanımla
        props: [
            'urunAdi', // String beklenen basit tanım
            'urunFiyat'
            // veya daha detaylı: { urunFiyat: Number } şeklinde tip belirterek
        ],
        template: `
            <div class="urun-karti">
                <h3>{{ urunAdi }}</h3> {# Propsları şablonda kullan #}
                <p>Fiyat: {{ urunFiyat }} TL</p>
                <button>Sepete Ekle</button>
            </div>
        ` // Şablon genellikle tek bir kök element içermeli
    });

Ebeveyn Bileşende (Ana Uygulama) Props Gönderme: Çocuğu kullandığınız yerde, HTML nitelikleri gibi prop isimlerini bağlarsınız. Eğer gönderilen veri dinamikse (`data`'dan geliyorsa), `v-bind:` veya kısası `:` kullanmalısınız.

HTML:
<div id="app">
    <h1>Ürün Listesi</h1>

    {# Ana uygulama data'sında bir ürün listesi olsun #}
    {# data() { return { urunler: [{ad: 'Laptop', fiyat: 15000}, {ad: 'Klavye', fiyat: 500}] } } #}

    {# v-for ile ürün listesini gez #}
    <ul>
        <li v-for="urun in urunler" :key="urun.ad">
            {# urun-karti bileşenini kullan ve propsları gönder #}
            {# urunAdi prop'una urun objesinin ad özelliğini bağla #}
            {# urunFiyat prop'una urun objesinin fiyat özelliğini bağla #}
            <urun-karti
                :urun-adi="urun.ad"    {# Kebab-case HTML attribute -> camelCase JS prop #}
                :urun-fiyat="urun.fiyat"
            ></urun-karti>
        </li>
    </ul>

</div>
{# İlgili Vue JS kodu bu HTML dosyasında script etiketleri içinde olmalı #}
Açıklama: `<urun-karti :urun-adi="urun.ad" ...>` ifadesi, `urun-karti` bileşenine `urun-adi` adında bir prop gönderir. `:urun-adi` 'v-bind:urun-adi'nin kısasıdır ve sağındaki değerin ('urun.ad') bir JavaScript ifadesi olduğunu ve data'dan geldiğini belirtir. Çocuk bileşen (`urun-karti`) bu `urun-adi` prop'unu kendi içinde `this.urunAdi` olarak veya şablonunda `{{ urunAdi }}` olarak kullanabilir.

5. Olaylar ($emit) İle Veri Gönderme (Child -> Parent)[/B]

Child bileşen bir olay (event) gerçekleştiğinde (örneğin bir butona tıklandığında), ebeveynine bir şeyler olduğunu bildirmesi gerekebilir. Child'dan Parent'a iletişim kurmanın temel yolu, özel olaylar yayınlamak (emit etmek)'tir. Child bileşen bir olay yayınlar, Parent bileşen ise bu olayı dinler ve bir metot çalıştırır.

Çocuk Bileşende Olay Yayınlama: Çocuk bileşenin bir metodu içinde `this.$emit('olayAdi', veri)` kullanılır.

JavaScript:
    // Ürün Kartı bileşeninin güncellenmiş hali (sepete ekleme özelliği ekliyoruz)
    app.component('urun-karti', {
        props: ['urunAdi', 'urunFiyat'],
        template: `
            <div class="urun-karti">
                <h3>{{ urunAdi }}</h3>
                <p>Fiyat: {{ urunFiyat }} TL</p>
                {# Buton tıklaninca 'sepete-ekle' adında bir olay yayınla #}
                {# Argüman olarak ürünün adını (this.urunAdi) Parent'a gönder #}
                <button @click="sepeteEkle">Sepete Ekle</button>
            </div>
        `,
        methods: {
            sepeteEkle() {
                // 'sepete-ekle' adında özel bir olay yayınla
                // Olayla birlikte 'this.urunAdi' değerini de Parent'a gönder
                this.$emit('sepete-ekle', this.urunAdi);
            }
        }
    });

Ebeveyn Bileşende (Ana Uygulama) Olay Dinleme: Çocuğu kullandığınız yerde, `v-on:` veya kısası `@` ile çocuk tarafından yayınlanan olayın adını dinlersiniz ve bir metodu bağlarsınız.

HTML:
<div id="app">
    <h1>Ürün Listesi</h1>
    <p>Sepetiniz: {{ sepet.length }} ürün</p> {# Ana uygulama data'sında 'sepet' listesi olsun #}

    <ul>
        <li v-for="urun in urunler" :key="urun.ad">
            <urun-karti
                :urun-adi="urun.ad"
                :urun-fiyat="urun.fiyat"
                {# urun-karti bileşeninin 'sepete-ekle' olayını dinle #}
                {# Olay olduğunda ana uygulamadaki 'sepeteUrunEkle' metodunu çağır #}
                {# $event, child tarafından emit edilen veriyi temsil eder (urunAdi) #}
                @sepete-ekle="sepeteUrunEkle($event)"
            ></urun-karti>
        </li>
    </ul>

</div>
[B]<script>[/B]
     const app = Vue.createApp({
        data() {
            return {
                urunler: [{ad: 'Laptop', fiyat: 15000}, {ad: 'Klavye', fiyat: 500}],
                sepet: [] // Sepet data'sı
            }
        },
        methods: {
            sepeteUrunEkle(eklenenUrunAdi) { // Child'dan gelen 'urunAdi' $event olarak bu metoda gelir
                console.log(eklenenUrunAdi + " sepete eklendi!");
                this.sepet.push(eklenenUrunAdi); // Sepet data'sına ekle (örnek)
            }
        }
        // Bileşen tanımı buraya veya yukarıya gelecek
    });

    // urun-karti bileşen tanımı yukarıdaki gibi burada olmalı

    app.mount('#app');
[B]</script>[/B]
Açıklama: `<urun-karti @sepete-ekle="sepeteUrunEkle($event)">` ifadesi, `urun-karti` bileşeninden `sepete-ekle` adında bir olay yayınlandığında ana uygulamadaki `sepeteUrunEkle` metodunun çalışacağını belirtir. `@sepete-ekle` 'v-on:sepete-ekle'nin kısasıdır. `sepeteUrunEkle($event)` çağrısı, child tarafından `this.$emit()` ile gönderilen veriyi (`this.urunAdi`) metodun parametresi olarak almanızı sağlar.

6. Tam Bir Vue.js Bileşen Örneği (Parent -> Child -> Parent İletişimi)[/B]

Aşağıdaki kod, bir `urun-karti` bileşeni tanımlayan, bu bileşeni ana uygulamada kullanan ve Props ile veri gönderip $emit ile olay yakalayan tam bir örnektir.

HTML:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Vue.js Bileşen Örneği</title>
    {# Vue 3 CDN linki #}
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
        .urun-karti {
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
            width: 200px;
            display: inline-block;
            margin-right: 10px;
        }
    </style>
</head>
<body>

    <div id="app">
        <h1>Ürün Listesi ve Sepetim</h1>
        <p>Sepetinizde [B]{{ sepet.length }}[/B] ürün var.</p> {# Ana uygulama data'sındaki sepetin boyutu #}
        <ul>
            <li v-for="(item, index) in sepet" :key="index">{{ item }}</li> {# Sepet içeriğini de listeleyelim #}
        </ul>

        <hr>

        {# Ürünleri listele ve her biri için urun-karti bileşeni kullan #}
        <div class="urun-listesi">
            <urun-karti
                v-for="urun in urunler" {# v-for ile urunler listesini gez #}
                :key="urun.id" {# Key olarak benzersiz ID kullan #}
                :urun-id="urun.id" {# id prop'u gönder #}
                :urun-adi="urun.ad" {# ad prop'u gönder #}
                :urun-fiyat="urun.fiyat" {# fiyat prop'u gönder #}
                @sepete-ekle="sepeteUrunEkle" {# urun-karti'ndan gelen 'sepete-ekle' olayını dinle, sepeteUrunEkle metodunu çağır #}
            ></urun-karti>
        </div>

    </div>

    [B]<script>[/B]
        const app = Vue.createApp({
            data() {
                return {
                    urunler: [ // Ana uygulama data'sındaki ürün listesi
                        { id: 1, ad: 'Laptop', fiyat: 15000 },
                        { id: 2, ad: 'Klavye', fiyat: 500 },
                        { id: 3, ad: 'Fare', fiyat: 200 }
                    ],
                    sepet: [] // Ana uygulama data'sındaki sepet listesi
                }
            },
            methods: {
                // urun-karti bileşeninden gelen 'sepete-ekle' olayını yakalayan metot
                // Child'dan emit edilen veri (urunId) otomatik olarak ilk parametre ($event) gelir
                sepeteUrunEkle(urunId) {
                    // Sepete eklenen ürünün bilgilerini bul (opsiyonel, ID'yi saklamak da yeterli olabilir)
                    const eklenenUrun = this.urunler.find(urun => urun.id === urunId);
                    if (eklenenUrun) {
                         this.sepet.push(eklenenUrun.ad); // Ürün adını sepete ekle (Örnek basitlik için)
                         console.log(`${eklenenUrun.ad} sepete eklendi (ID: ${urunId})`);
                         alert(`${eklenenUrun.ad} sepete eklendi!`);
                    }
                }
            }
            // Bileşen tanımı aşağıda yapılacak
        });

        // urun-karti bileşen tanımı (Global kayıt)
        app.component('urun-karti', {
            // Beklediği propslar (ebeveynden gelecek veriler)
            props: {
                urunId: Number, // ID number tipinde bekleniyor
                urunAdi: String, // Ad String tipinde bekleniyor
                urunFiyat: Number // Fiyat Number tipinde bekleniyor
            },
            template: `
                <div class="urun-karti">
                    <h3>{{ urunAdi }}</h3> {# Propsları şablonda kullan #}
                    <p>Fiyat: {{ urunFiyat }} TL</p>
                    {# Butona tıklandığında 'sepete-ekle' olayını yayınla #}
                    {# Olayla birlikte urunId prop'unu (ürünün ID'sini) ebeveyne gönder #}
                    <button @click="sepeteEkle">Sepete Ekle</button>
                </div>
            `,
            methods: {
                sepeteEkle() {
                    // 'sepete-ekle' adında özel bir olay yayınla
                    // Olayla birlikte 'this.urunId' prop'unun değerini (ürünün ID'sini) ebeveyne gönder
                    this.$emit('sepete-ekle', this.urunId);
                }
            }
        });

        // Vue uygulamasını #app elementine bağla
        app.mount('#app');
    [B]</script>[/B]

</body>
</html>
Bu kodu bir metin düzenleyiciye yapıştırın, "component_example.html" olarak kaydedin ve tarayıcınızda açın. Her ürün kartının bağımsız olduğunu, Propslar aracılığıyla farklı ürün bilgilerini gösterdiğini ve 'Sepete Ekle' butonuna tıklayarak ana uygulamadaki 'sepet' data'sını güncellediğini gözlemleyin.

8. Tek Dosya Bileşenleri (.vue) Kavramı (Çok Kısa)[/B]

Yukarıdaki örnekte bileşen şablonunu ('template') JavaScript kodu içinde bir string olarak tanımladık. Gerçek Vue projelerinde şablon (template), JavaScript mantığı (script) ve stil (style) genellikle `.vue` uzantılı tek bir dosyada bulunur (SFC - Single-File Component). Bu dosyalar Vue CLI veya Vite gibi modern derleme araçları (build tools) gerektirir.

Kod:
<template>
  <div class="my-component">
    <h1>{{ title }}</h1>
    <button @click="handleClick">Tıkla</button>
  </div>
</template>

<script>
export default { // JavaScript mantığı
  props: ['title'],
  methods: {
    handleClick() {
      alert('Buton Tıklandı!');
    }
  }
}
</script>

<style scoped> // Stiller sadece bu bileşene uygulanır
.my-component {
  border: 1px solid blue;
}
</style>
Açıklama: SFC'ler, bileşenleri daha düzenli ve modüler hale getirir ancak bunları kullanmak için bir proje kurulumu ve derleme süreci gereklidir. CDN yöntemi temelleri öğrenmek için harikadır, ancak gerçek projeler için SFC'ler standarttır.

Sıra Sizde![/B]

Vue.js'te bileşenler ve veri iletişiminin temellerini gördük.

  • Kendi basit bileşeninizi tanımlayın (örneğin bir `ButonSayac` bileşeni, içinde kendi sayacı ve artırma butonu olsun). Global olarak kaydedin ve ana uygulamada birkaç kez kullanın. Sayaçlarının bağımsız olduğunu doğrulayın.
  • Bir `Selamlayici` bileşeni tanımlayın, `isim` adında bir prop beklesin ve şablonunda "Merhaba, {{ isim }}!" yazsın. Ana uygulamada farklı isimlerle bu bileşeni kullanın (`<selamlayici :isim="'Ali'"></selamlayici>`).
  • `UrunKarti` örneğini tekrar kodlayın ve çalıştırın. Sepete ekleme butonuna tıkladığınızda ana uygulamadaki sepetin güncellendiğini gözlemleyin. `$emit` ile gönderilen veriye (urunId) ana uygulamadaki metottan erişebildiğinizi doğrulayın.
  • `Props`'ları yanlışlıkla child bileşenin içinde değiştirmeye çalışın (örn: `this.urunAdi = 'Yeni Ad';`) ve Vue'nun uyarı verdiğini görün (Propslar readonly'dir).
Bileşen tanımı, global kayıt, Props gönderme ve alma, `$emit` ile olay yayınlama/dinleme veya ebeveyn-çocuk iletişimi hakkında aklınıza takılan soruları çekinmeden bu konu altında sorabilirsiniz.

Serinin Geleceği?[/B]

Bileşenler, modern frontend frameworklerinin kalbidir ve bunları anlamak Vue.js'te ilerlemek için kritik öneme sahiptir.

Seriyi buradan sonra nasıl devam ettirelim?

  • Vue.js'te daha ileri bileşen konuları (Lokal kayıt, Component Lifecycle Hooks, Slots ile içerik dağıtımı, Form Input Binding - v-model detayları)?
  • Vue Router ile Tek Sayfa Uygulama (SPA) navigasyonu?
  • Vuex veya Pinia ile Merkezi State Management (uygulamanın paylaşılan verilerini yönetme)?
  • Vue ile API çağrıları yapma (Fetch API veya Axios kullanımı) - Ön yüzü arka yüze bağlama (Konu 25'in Vue bağlamında uygulaması)?
  • Diğer popüler JavaScript Frontend Frameworklerine giriş (React veya Angular temelleri)?
  • Webpack/Vite gibi Modül Paketleyiciler ve modern Frontend geliştirme ortamı?
  • Veya başka önerileriniz mi var?
Geri bildirimleriniz ve önerileriniz serinin geleceğini şekillendirecektir.

Umarım bu konu, Vue.js'te componentlerle düşünmeye başlamanızda faydalı olmuştur. Görüşmek üzere!



Bu konu, "Hazır Kod Bankası" serisinin yirmi sekizinci parçasıdır ve "Yazılım Bilgi ve Yeni Başlayanlar İçin" kategorisi altında paylaşılmıştır.
 

Şu an konuyu görüntüleyenler

Tema özelleştirme sistemi

Bu menüden forum temasının bazı alanlarını kendinize özel olarak düzenleye bilirsiniz

Zevkini yansıtan rengi seç

Geniş / Dar görünüm

Temanızı geniş yada dar olarak kullanmak için kullanabileceğiniz bir yapıyı kontrolünü sağlayabilirsiniz.

Izgara görünümlü forum listesi

Forum listesindeki düzeni ızgara yada sıradan listeleme tarzındaki yapının kontrolünü sağlayabilirsiniz.

Resimli ızgara modu

Izgara forum listesinde resimleri açıp/kapatabileceğiniz yapının kontrolünü sağlayabilirsiniz.

Kenar çubuğunu kapat

Kenar çubuğunu kapatarak forumdaki kalabalık görünümde kurtulabilirsiniz.

Sabit kenar çubuğu

Kenar çubuğunu sabitleyerek daha kullanışlı ve erişiminizi kolaylaştırabilirsiniz.

Köşe kıvrımlarını kapat

Blokların köşelerinde bulunan kıvrımları kapatıp/açarak zevkinize göre kullanabilirsiniz.

Geri