Dev to webs {Coding…}

เรียนรู้การพัฒนาซอฟเวอร์ เพื่อความรู้ที่ยั่งยืน

บทที่ 46: การสร้าง Component Reusable


1. ความสำคัญของ Component Reusable

Component Reusable คือ Component ที่ออกแบบมาให้สามารถใช้งานซ้ำได้ในหลายส่วนของโปรเจกต์

  • ช่วยลดความซ้ำซ้อนของโค้ด
  • เพิ่มความง่ายในการบำรุงรักษา
  • ทำให้โครงสร้างโปรเจกต์ชัดเจน

การสร้าง Component Reusable ใน Alpine.js สามารถทำได้โดยการใช้ x-data, Props, และ Slot


2. การออกแบบ Component พื้นฐาน

ตัวอย่าง 1: ปุ่ม Reusable
<div x-data="{ label: 'Click me', action: () => alert('Button clicked!') }">
    <button @click="action" class="px-4 py-2 bg-blue-500 text-white rounded">
        <span x-text="label"></span>
    </button>
</div>

คำอธิบาย:

  • ใช้ State label และ action เพื่อกำหนดข้อความและฟังก์ชัน
  • สามารถเปลี่ยนค่า label และ action ได้เมื่อใช้งาน Component

3. การใช้ Template เพื่อสร้าง Component Reusable

ตัวอย่าง 2: การสร้าง Card Component
<template id="card-template">
    <div class="p-4 border rounded shadow">
        <h2 class="text-lg font-bold" x-text="title"></h2>
        <p class="text-gray-600" x-text="content"></p>
        <button @click="action" class="mt-2 px-4 py-2 bg-blue-500 text-white rounded">
            <span x-text="buttonLabel"></span>
        </button>
    </div>
</template>

<div x-data="{ title: 'Card Title', content: 'This is card content.', buttonLabel: 'Click', action: () => alert('Card clicked!') }">
    <div x-init="$el.innerHTML = document.getElementById('card-template').innerHTML"></div>
</div>

คำอธิบาย:

  • ใช้ <template> เพื่อเก็บโครงสร้าง Component
  • Component สามารถปรับแต่งข้อความและฟังก์ชันได้ด้วย State

4. การสร้าง Component ซ้ำในลูป

ตัวอย่าง 3: วนลูปเพื่อสร้าง Component หลายตัว
<div x-data="{ cards: [
    { title: 'Card 1', content: 'Content for card 1', buttonLabel: 'Click Me', action: () => alert('Card 1 clicked!') },
    { title: 'Card 2', content: 'Content for card 2', buttonLabel: 'Click Me', action: () => alert('Card 2 clicked!') }
] }">
    <template x-for="card in cards" :key="card.title">
        <div class="p-4 border rounded shadow">
            <h2 class="text-lg font-bold" x-text="card.title"></h2>
            <p class="text-gray-600" x-text="card.content"></p>
            <button @click="card.action" class="mt-2 px-4 py-2 bg-blue-500 text-white rounded">
                <span x-text="card.buttonLabel"></span>
            </button>
        </div>
    </template>
</div>

คำอธิบาย:

  • ใช้ x-for วนลูปเพื่อสร้าง Component หลายตัวจากข้อมูลใน Array
  • แต่ละ Card Component มีค่าของตัวเองที่กำหนดใน Array

5. การใช้ Slot สำหรับ Component Reusable

ตัวอย่าง 4: Component แบบ Slot
<template id="slot-component">
    <div class="p-4 border rounded shadow">
        <slot></slot>
    </div>
</template>

<div>
    <div x-data x-init="$el.innerHTML = document.getElementById('slot-component').innerHTML">
        <h2 class="text-lg font-bold">Custom Content</h2>
        <p>This content is passed to the slot.</p>
    </div>
</div>

คำอธิบาย:

  • ใช้ <slot> เพื่อสร้าง Component ที่รองรับเนื้อหาที่กำหนดเอง
  • สามารถส่งเนื้อหาเข้ามาใน Component ผ่านโครงสร้าง HTML

6. การส่ง Props ให้ Component Reusable

ตัวอย่าง 5: Component พร้อม Props
<div x-data="{ createButton(label, action) { return { label, action }; } }">
    <template x-data="createButton('Submit', () => alert('Submitted!'))">
        <button @click="action" class="px-4 py-2 bg-green-500 text-white rounded">
            <span x-text="label"></span>
        </button>
    </template>
</div>

คำอธิบาย:

  • ฟังก์ชัน createButton สร้าง State สำหรับ Component
  • สามารถส่ง label และ action เป็น Props เพื่อกำหนดค่าของปุ่ม

7. การจัดการ State ร่วมกันใน Component

ตัวอย่าง 6: ใช้ Alpine.store สำหรับ State ร่วมกัน
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.store('sharedState', {
            count: 0
        });
    });
</script>

<div>
    <div x-data>
        <button @click="$store.sharedState.count++">Increment</button>
    </div>
    <div x-data>
        <p>Shared Count: <span x-text="$store.sharedState.count"></span></p>
    </div>
</div>

คำอธิบาย:

  • ใช้ Alpine.store เพื่อจัดการ State ที่แชร์ระหว่าง Component
  • ลดความซ้ำซ้อนในการประกาศ State เดียวกันในหลาย Component

8. การสร้าง Component Reusable ที่ยืดหยุ่น

ตัวอย่าง 7: Component แบบ Dynamic
<div x-data="{ createCard(title, content, buttonLabel, action) { 
        return { title, content, buttonLabel, action }; 
    }, cards: [] }">
    <button @click="cards.push(createCard('Dynamic Title', 'Dynamic Content', 'Click Me', () => alert('Dynamic Clicked!')))">
        Add Card
    </button>
    <template x-for="card in cards" :key="card.title">
        <div class="p-4 border rounded shadow">
            <h2 class="text-lg font-bold" x-text="card.title"></h2>
            <p class="text-gray-600" x-text="card.content"></p>
            <button @click="card.action" class="mt-2 px-4 py-2 bg-blue-500 text-white rounded">
                <span x-text="card.buttonLabel"></span>
            </button>
        </div>
    </template>
</div>

คำอธิบาย:

  • ฟังก์ชัน createCard สร้างข้อมูลสำหรับ Card Component
  • สามารถเพิ่ม Card ใหม่ได้แบบ Dynamic

สรุป

ในบทนี้ คุณได้เรียนรู้การสร้าง Component Reusable ใน Alpine.js ตัวอย่างครอบคลุมการสร้าง Component แบบฟังก์ชัน, การใช้ Slot, การส่ง Props, และการแชร์ State Component Reusable ช่วยลดการเขียนโค้ดซ้ำ เพิ่มความยืดหยุ่น และทำให้การพัฒนาโปรเจกต์มีประสิทธิภาพมากขึ้น!