Proje Detayları

Adım Adım Geliştirme

Bu bölümde, özel web bileşenlerini adım adım nasıl geliştirebileceğinizi öğreneceksiniz. Her adımda, ilgili kod parçalarını ve açıklamalarını bulacaksınız.

Adım 1: Proje Yapısını Oluşturma

İlk olarak, projemiz için gerekli dosyaları oluşturalım:

  • index.html - Ana HTML dosyası
  • styles.css - Genel CSS stil dosyası
  • components/ - Bileşenlerimizi içeren klasör
    • custom-card.js - Özel kart bileşeni
  • app.js - Ana JavaScript dosyası
index.html
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Component Oluşturma</title>
    <link rel="stylesheet" href="styles.css">
    <script src="components/custom-card.js" type="module"></script>
    <script src="app.js" type="module"></script>
</head>
<body>
    <div class="container">
        <h1>Web Component Örneği</h1>
        
        <div class="controls">
            <button id="changeTitle">Başlığı Değiştir</button>
            <button id="changeContent">İçeriği Değiştir</button>
            <button id="changeTheme">Temayı Değiştir</button>
        </div>
        
        <div class="component-container">
            <!-- Web Component'i burada kullanacağız -->
            <custom-card 
                title="Merhaba Web Components!" 
                content="Bu özel bir web bileşenidir. Yeniden kullanılabilir ve kapsüllenmiş bir yapıya sahiptir."
                theme="primary">
            </custom-card>
        </div>
    </div>
</body>
</html>

Adım 2: Temel CSS Stillerini Ekleme

Genel sayfa stillerini tanımlayalım:

styles.css
/* Genel Stiller */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #f4f7f6;
    color: #333;
    line-height: 1.6;
}

.container {
    width: 100%;
    max-width: 800px;
    margin: 40px auto;
    padding: 20px;
}

h1 {
    text-align: center;
    margin-bottom: 30px;
    color: #2c3e50;
}

/* Kontrol Butonları */
.controls {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin-bottom: 30px;
}

.controls button {
    background-color: #3498db;
    color: white;
    border: none;
    padding: 10px 15px;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
}

.controls button:hover {
    background-color: #2980b9;
}

/* Bileşen Konteyneri */
.component-container {
    display: flex;
    justify-content: center;
    padding: 20px;
}

Adım 3: İlk Web Component'i Oluşturma

Şimdi, özel bir kart bileşeni oluşturalım. Bu bileşen, başlık, içerik ve tema özelliklerine sahip olacak:

components/custom-card.js
// Custom Card Component
class CustomCard extends HTMLElement {
    constructor() {
        super();
        
        // Shadow DOM oluştur
        this.attachShadow({ mode: 'open' });
        
        // Bileşenin iç durumu (state)
        this.state = {
            title: this.getAttribute('title') || 'Kart Başlığı',
            content: this.getAttribute('content') || 'Kart içeriği burada yer alacak.',
            theme: this.getAttribute('theme') || 'primary'
        };
        
        // Bileşeni render et
        this.render();
    }
    
    // Bileşeni render etme metodu
    render() {
        // Tema renklerini tanımla
        const themeColors = {
            primary: '#3498db',
            secondary: '#2ecc71',
            danger: '#e74c3c',
            warning: '#f39c12',
            info: '#1abc9c'
        };
        
        // Seçilen tema rengini al
        const themeColor = themeColors[this.state.theme] || themeColors.primary;
        
        // Shadow DOM içeriğini oluştur
        this.shadowRoot.innerHTML = `
            
                :host {
                    display: block;
                    width: 100%;
                    max-width: 350px;
                    margin: 0 auto;
                }
                
                .card {
                    border-radius: 8px;
                    overflow: hidden;
                    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
                    background-color: white;
                    transition: transform 0.3s, box-shadow 0.3s;
                }
                
                .card:hover {
                    transform: translateY(-5px);
                    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
                }
                
                .card-header {
                    padding: 15px;
                    background-color: ${themeColor};
                    color: white;
                    font-weight: bold;
                    font-size: 1.2rem;
                }
                
                .card-content {
                    padding: 15px;
                }
                
                .card-footer {
                    padding: 15px;
                    background-color: #f5f5f5;
                    display: flex;
                    justify-content: flex-end;
                }
                
                .card-btn {
                    background-color: ${themeColor};
                    color: white;
                    border: none;
                    padding: 8px 12px;
                    border-radius: 4px;
                    cursor: pointer;
                    transition: opacity 0.3s;
                }
                
                .card-btn:hover {
                    opacity: 0.8;
                }
            
            
            
                ${this.state.title}
                ${this.state.content}
                
                    Detaylar
                
            
        `;
        
        // Detaylar butonuna tıklama olayı ekle
        const detailsButton = this.shadowRoot.querySelector('.card-btn');
        detailsButton.addEventListener('click', () => {
            // Özel olay oluştur ve dışarıya gönder
            const event = new CustomEvent('card-click', {
                bubbles: true,
                composed: true, // Shadow DOM sınırlarını aşmasını sağlar
                detail: {
                    title: this.state.title,
                    content: this.state.content
                }
            });
            this.dispatchEvent(event);
        });
    }
    
    // Özellik değişikliklerini izle
    static get observedAttributes() {
        return ['title', 'content', 'theme'];
    }
    
    // Özellik değiştiğinde çağrılır
    attributeChangedCallback(name, oldValue, newValue) {
        if (oldValue !== newValue) {
            this.state[name] = newValue;
            this.render();
        }
    }
    
    // Getter ve setter metodları
    get title() {
        return this.state.title;
    }
    
    set title(value) {
        this.setAttribute('title', value);
    }
    
    get content() {
        return this.state.content;
    }
    
    set content(value) {
        this.setAttribute('content', value);
    }
    
    get theme() {
        return this.state.theme;
    }
    
    set theme(value) {
        this.setAttribute('theme', value);
    }
}

// Özel elementi tarayıcıya kaydet
customElements.define('custom-card', CustomCard);

Adım 4: Ana JavaScript Dosyasını Oluşturma

Şimdi, web bileşenimizi kontrol etmek için ana JavaScript dosyasını oluşturalım:

app.js
// DOM elementlerini seçme
const changeTitle = document.getElementById('changeTitle');
const changeContent = document.getElementById('changeContent');
const changeTheme = document.getElementById('changeTheme');
const customCard = document.querySelector('custom-card');

// Başlık değiştirme butonu
changeTitle.addEventListener('click', () => {
    const titles = [
        'Web Components Harika!',
        'Özel Elementler Oluşturma',
        'Shadow DOM ile Kapsülleme',
        'Yeniden Kullanılabilir Bileşenler',
        'Modern Web Geliştirme'
    ];
    
    // Rastgele bir başlık seç
    const randomTitle = titles[Math.floor(Math.random() * titles.length)];
    
    // Bileşenin başlık özelliğini güncelle
    customCard.title = randomTitle;
});

// İçerik değiştirme butonu
changeContent.addEventListener('click', () => {
    const contents = [
        'Web Components, tarayıcı destekli özel HTML elementleri oluşturmanızı sağlar.',
        'Shadow DOM, stil ve davranış kapsüllemesi için güçlü bir araçtır.',
        'Özel elementler, HTML\'i genişletmenize ve kendi etiketlerinizi tanımlamanıza olanak tanır.',
        'Bileşen tabanlı geliştirme, kodunuzu daha modüler ve bakımı kolay hale getirir.',
        'Web Components, framework bağımsız çalışır ve herhangi bir web sayfasında kullanılabilir.'
    ];
    
    // Rastgele bir içerik seç
    const randomContent = contents[Math.floor(Math.random() * contents.length)];
    
    // Bileşenin içerik özelliğini güncelle
    customCard.content = randomContent;
});

// Tema değiştirme butonu
changeTheme.addEventListener('click', () => {
    const themes = ['primary', 'secondary', 'danger', 'warning', 'info'];
    
    // Rastgele bir tema seç
    const randomTheme = themes[Math.floor(Math.random() * themes.length)];
    
    // Bileşenin tema özelliğini güncelle
    customCard.theme = randomTheme;
});

// Kart tıklama olayını dinle
document.addEventListener('card-click', (event) => {
    console.log('Kart tıklandı:', event.detail);
    alert(`Kart Detayları:\nBaşlık: ${event.detail.title}\nİçerik: ${event.detail.content}`);
});

Adım 5: Web Component'i Genişletme

Şimdi, özel kartımızı daha esnek hale getirmek için bazı ek özellikler ekleyelim:

components/custom-card.js (genişletilmiş)
// Custom Card Component (Genişletilmiş)
class CustomCard extends HTMLElement {
    constructor() {
        super();
        
        // Shadow DOM oluştur
        this.attachShadow({ mode: 'open' });
        
        // Bileşenin iç durumu (state)
        this.state = {
            title: this.getAttribute('title') || 'Kart Başlığı',
            content: this.getAttribute('content') || 'Kart içeriği burada yer alacak.',
            theme: this.getAttribute('theme') || 'primary',
            image: this.getAttribute('image') || '',
            buttonText: this.getAttribute('button-text') || 'Detaylar',
            elevation: this.getAttribute('elevation') || 'medium'
        };
        
        // Bileşeni render et
        this.render();
    }
    
    // Bileşeni render etme metodu
    render() {
        // Tema renklerini tanımla
        const themeColors = {
            primary: '#3498db',
            secondary: '#2ecc71',
            danger: '#e74c3c',
            warning: '#f39c12',
            info: '#1abc9c'
        };
        
        // Yükseklik (elevation) değerlerini tanımla
        const elevationValues = {
            low: '0 2px 5px rgba(0, 0, 0, 0.1)',
            medium: '0 4px 8px rgba(0, 0, 0, 0.1)',
            high: '0 8px 16px rgba(0, 0, 0, 0.15)'
        };
        
        // Seçilen tema rengini ve yüksekliği al
        const themeColor = themeColors[this.state.theme] || themeColors.primary;
        const shadowValue = elevationValues[this.state.elevation] || elevationValues.medium;
        
        // Shadow DOM içeriğini oluştur
        this.shadowRoot.innerHTML = `
            
                :host {
                    display: block;
                    width: 100%;
                    max-width: 350px;
                    margin: 0 auto;
                }
                
                .card {
                    border-radius: 8px;
                    overflow: hidden;
                    box-shadow: ${shadowValue};
                    background-color: white;
                    transition: transform 0.3s, box-shadow 0.3s;
                }
                
                .card:hover {
                    transform: translateY(-5px);
                    box-shadow: 0 12px 20px rgba(0, 0, 0, 0.2);
                }
                
                .card-header {
                    padding: 15px;
                    background-color: ${themeColor};
                    color: white;
                    font-weight: bold;
                    font-size: 1.2rem;
                }
                
                .card-image {
                    width: 100%;
                    height: auto;
                    display: ${this.state.image ? 'block' : 'none'};
                }
                
                .card-content {
                    padding: 15px;
                }
                
                .card-footer {
                    padding: 15px;
                    background-color: #f5f5f5;
                    display: flex;
                    justify-content: flex-end;
                }
                
                .card-btn {
                    background-color: ${themeColor};
                    color: white;
                    border: none;
                    padding: 8px 12px;
                    border-radius: 4px;
                    cursor: pointer;
                    transition: opacity 0.3s;
                }
                
                .card-btn:hover {
                    opacity: 0.8;
                }
                
                /* Slot için stil */
                ::slotted(*) {
                    margin: 10px 0;
                }
            
            
            
                ${this.state.title}
                ${this.state.image ? `` : ''}
                
                    ${this.state.content}
                     
                
                
                    ${this.state.buttonText}
                
            
        `;
        
        // Detaylar butonuna tıklama olayı ekle
        const detailsButton = this.shadowRoot.querySelector('.card-btn');
        detailsButton.addEventListener('click', () => {
            // Özel olay oluştur ve dışarıya gönder
            const event = new CustomEvent('card-click', {
                bubbles: true,
                composed: true, // Shadow DOM sınırlarını aşmasını sağlar
                detail: {
                    title: this.state.title,
                    content: this.state.content,
                    image: this.state.image
                }
            });
            this.dispatchEvent(event);
        });
    }
    
    // Özellik değişikliklerini izle
    static get observedAttributes() {
        return ['title', 'content', 'theme', 'image', 'button-text', 'elevation'];
    }
    
    // Özellik değiştiğinde çağrılır
    attributeChangedCallback(name, oldValue, newValue) {
        if (oldValue !== newValue) {
            // button-text gibi kebab-case özellikleri camelCase'e dönüştür
            const propName = name.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
            this.state[propName] = newValue;
            this.render();
        }
    }
    
    // Yaşam döngüsü metodları
    connectedCallback() {
        console.log('Bileşen DOM\'a eklendi');
    }
    
    disconnectedCallback() {
        console.log('Bileşen DOM\'dan kaldırıldı');
    }
    
    adoptedCallback() {
        console.log('Bileşen başka bir dokümana taşındı');
    }
    
    // Getter ve setter metodları
    get title() {
        return this.state.title;
    }
    
    set title(value) {
        this.setAttribute('title', value);
    }
    
    get content() {
        return this.state.content;
    }
    
    set content(value) {
        this.setAttribute('content', value);
    }
    
    get theme() {
        return this.state.theme;
    }
    
    set theme(value) {
        this.setAttribute('theme', value);
    }
    
    get image() {
        return this.state.image;
    }
    
    set image(value) {
        this.setAttribute('image', value);
    }
    
    get buttonText() {
        return this.state.buttonText;
    }
    
    set buttonText(value) {
        this.setAttribute('button-text', value);
    }
    
    get elevation() {
        return this.state.elevation;
    }
    
    set elevation(value) {
        this.setAttribute('elevation', value);
    }
}

// Özel elementi tarayıcıya kaydet
customElements.define('custom-card', CustomCard);

Adım 6: Slot Kullanımı ve İçerik Ekleme

Web bileşenimize dışarıdan HTML içeriği eklemek için slot kullanımını gösterelim:

index.html (güncellenmiş)
<!-- ... (önceki kodlar) ... -->

<div class="component-container">
    <custom-card 
        title="Merhaba Web Components!" 
        content="Bu özel bir web bileşenidir. Yeniden kullanılabilir ve kapsüllenmiş bir yapıya sahiptir."
        theme="primary"
        image="https://picsum.photos/350/200"
        button-text="Daha Fazla"
        elevation="medium">
        
        <!-- Slot içeriği -->
        <div style="margin-top: 15px; padding: 10px; background-color: #f8f9fa; border-radius: 5px;">
            <h3>Ek Bilgiler</h3>
            <p>Bu içerik, slot kullanılarak bileşen içine eklenmiştir.</p>
            <ul>
                <li>Shadow DOM ile kapsülleme</li>
                <li>Özel özellikler ve olaylar</li>
                <li>Yeniden kullanılabilir yapı</li>
            </ul>
        </div>
        
    </custom-card>
</div>

<!-- ... (sonraki kodlar) ... -->

Adım 7: Uygulamayı Test Etme

Şimdi uygulamanızı test etme zamanı! Aşağıdaki adımları izleyin:

  1. Tüm dosyaları (index.htmlstyles.cssapp.jscomponents/custom-card.js) oluşturun.
  2. Dosyaları bir web sunucusu üzerinden çalıştırın (yerel geliştirme sunucusu veya canlı sunucu).
  3. Tarayıcıda sayfayı açın ve özel kartın doğru şekilde göründüğünü kontrol edin.
  4. Başlık, içerik ve tema değiştirme butonlarını test edin.
  5. Kart üzerindeki "Detaylar" butonuna tıklayarak özel olayın çalıştığını doğrulayın.
  6. Slot içeriğinin doğru şekilde göründüğünü kontrol edin.
  7. Farklı tarayıcılarda uyumluluğu test edin.

Not: Web Components API, modern tarayıcıların çoğunda desteklenmektedir. Ancak, eski tarayıcılar için polyfill kullanmanız gerekebilir. webcomponents/polyfills projesini inceleyebilirsiniz.

Projeyi Geliştirme

Temel web bileşeni uygulamasını başarıyla oluşturduktan sonra, aşağıdaki özelliklerle projenizi geliştirebilirsiniz:

1. Bileşen Kütüphanesi Oluşturma

Farklı türde web bileşenleri oluşturarak bir kütüphane geliştirin:

  • Özel butonlar
  • Form elementleri (özel giriş alanları, seçim kutuları vb.)
  • Modal/dialog bileşenleri
  • Sekmeler (tabs) bileşeni
  • Açılır menüler

2. Tema Sistemi

Bileşenleriniz için kapsamlı bir tema sistemi oluşturun:

  • CSS değişkenleri (variables) kullanarak tema desteği
  • Açık/koyu tema geçişi
  • Özelleştirilebilir renk paletleri

3. Form Doğrulama Bileşeni

Özel bir form doğrulama bileşeni oluşturun:

  • Farklı doğrulama kuralları (e-posta, şifre, sayı vb.)
  • Hata mesajları gösterme
  • Form gönderme olayını yönetme

4. Veri Bağlama (Data Binding)

Bileşenlerinize veri bağlama özellikleri ekleyin:

  • Tek yönlü veri bağlama
  • İki yönlü veri bağlama
  • Veri değişikliklerini izleme ve tepki verme

5. Animasyon ve Geçiş Efektleri

Bileşenlerinize animasyon ve geçiş efektleri ekleyin:

  • Görünüm/kaybolma animasyonları
  • Etkileşimli animasyonlar
  • Sayfa geçişleri

Geliştirme Zorlukları

Web bileşenleri uygulamanızı daha da geliştirmek için aşağıdaki zorlukları deneyebilirsiniz:

  1. Bileşen Kompozisyonu: Birden fazla web bileşenini bir araya getirerek daha karmaşık bileşenler oluşturun (örneğin, bir form bileşeni içinde özel giriş alanları ve butonlar).
  2. Durum Yönetimi: Bileşenler arası durum paylaşımı için basit bir durum yönetim sistemi oluşturun.
  3. Erişilebilirlik: Web bileşenlerinizi ARIA öznitelikleri ve klavye navigasyonu ile erişilebilir hale getirin.
  4. Lazy Loading: Bileşenlerin ihtiyaç duyulduğunda yüklenmesini sağlayan bir sistem oluşturun.
  5. Framework Entegrasyonu: Web bileşenlerinizi React, Vue veya Angular gibi popüler JavaScript framework'leri ile entegre edin.

Sonuç ve Öğrenilen Dersler

Bu projede, Web Components API kullanarak özel HTML elementleri oluşturduk. Bu süreçte şunları öğrendik:

  • Custom Elements API ile özel HTML elementleri tanımlama
  • Shadow DOM kullanarak stil ve davranış kapsüllemesi yapma
  • HTML Templates ve slot kullanarak içerik ekleme
  • Özel elementlere özellikler ve olaylar ekleme
  • Bileşenler arası iletişim kurma
  • Yeniden kullanılabilir ve modüler kod yazma

Web Components, modern web geliştirmenin önemli bir parçasıdır ve framework bağımsız, yeniden kullanılabilir bileşenler oluşturmanıza olanak tanır. Bu teknoloji, web uygulamalarınızı daha modüler, bakımı kolay ve ölçeklenebilir hale getirmenize yardımcı olur.

Öğrendiğiniz bu becerileri kullanarak, kendi bileşen kütüphanenizi oluşturabilir ve farklı projelerde kullanabilirsiniz. Ayrıca, popüler web bileşeni kütüphanelerini (lit-element, Stencil, Polymer vb.) keşfederek daha gelişmiş uygulamalar geliştirebilirsiniz.