- 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.
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');
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 #}
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ı #}
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]
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>
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>
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).
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?
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.