15: DOM Manipulation

เชื่อมต่อ JavaScript เข้ากับ HTML ด้วย DOM

DOM คืออะไร?

DOM (Document Object Model) คือโครงสร้างของหน้าเว็บที่แปลง HTML ให้เป็น Object เพื่อให้ JavaScript เข้าไป หยิบ (Select), แก้ไข (Manipulate), และ สั่งงาน ได้

1. การหยิบ Element (Selectors)

ก่อนจะเปลี่ยน หรือสั่งงานอะไร จะต้องเลือก Element ที่ต้องการ จาก HTML Elements หลาย ๆ อันในหน้าเว็บให้ถูกต้องก่อน

ตัวอย่าง HTML (สำหรับทดสอบ)
HTML
<!-- 1. หัวข้อหลัก (มี ID) -->
<h1 id="title">Welcome</h1>

<!-- 2. รายการผลไม้ (มี Class เหมือนกันหลายตัว) -->
<ul>
    <li class="fruit">Apple</li>
    <li class="fruit">Banana</li>
    <li class="fruit">Orange</li>
</ul>
1.1 document.querySelector()

หยิบ "ตัวแรกที่เจอ" (ได้ของชิ้นเดียว)

💻 JS Code:
JS
// หยิบด้วย ID (#)
let h1 = document.querySelector("#title");
console.log(h1);
📄 Result (สิ่งที่ได้):
<h1 id="title">Welcome</h1>
1.2 document.querySelectorAll()

หยิบ "ทุกตัวที่เจอ" (ได้เป็น List)

💻 JS Code:
JS
// หยิบด้วย Class (.)
let list = document.querySelectorAll(".fruit");
console.log(list);
📄 Result (สิ่งที่ได้):
NodeList(3) [
  <li class="fruit">Apple</li>,
  <li class="fruit">Banana</li>,
  <li class="fruit">Orange</li>
]

2. การแก้ไข (Manipulation)

พอหยิบมาได้แล้ว ก็จะสามารถสั่งให้ Element ที่หยิบมาเปลี่ยนแปลงได้

คำสั่ง หน้าที่ ตัวอย่าง
element.innerText เปลี่ยนข้อความข้างใน title.innerText = "สวัสดีชาวโลก";
element.innerHTML เปลี่ยนไส้ใน (ใส่ HTML Tag ได้)
⚠️ ล้างของเก่าทิ้งหมด
box.innerHTML = "<b>ตัวหนา</b>";
element.insertAdjacentHTML
(position, text)
แทรก HTML โดย ไม่ลบของเก่า
เลือกตำแหน่ง (position) ได้ 4 จุด:
  • "beforebegin": ก่อนเริ่ม (บนกล่อง)
  • "afterbegin": หลังเริ่ม (ในกล่อง บนสุด)
  • "beforeend": ก่อนจบ (ในกล่อง ล่างสุด)
  • "afterend": หลังจบ (ล่างกล่อง)
list.insertAdjacentHTML("beforeend", "<li>New</li>");
element.classList จัดการ Class CSS box.classList.add("active");
box.classList.remove("hide");
box.classList.toggle("dark");
element.setAttribute() เปลี่ยน Attribute (เช่น src, href) img.setAttribute("src", "cat.jpg");
element.style เปลี่ยน CSS โดยตรง (ใช้ CamelCase) box.style.backgroundColor = "red";
เพิ่มเติม: สั่งงานด้วยการ Click

ปกติ JS จะรันทันทีที่เปิดเว็บ แต่ถ้าอยากให้ "กดปุ่มก่อนค่อยรัน" ต้องใช้ onclick ใน HTML

HTML
<!-- เมื่อกดปุ่ม -> เรียกฟังก์ชัน changeColor() -->
<button onclick="changeColor()">กดฉันสิ</button>
JS
function changeColor() {
    // โค้ดในนี้จะทำงานเมื่อปุ่มถูกกดเท่านั้น!
    alert("ปุ่มถูกกดแล้วจ้า!");
}

3. ตัวอย่างการนำไปใช้จริง: Dark Mode Toggle

มาดูเทคนิคยอดฮิตอย่างการทำ "Dark Mode" กัน ว่าเบื้องหลังมันทำงานอย่างไร (ใช้ความรู้เรื่อง classList ที่เรียนไป)

Example: Dark Mode Card

ลองกดปุ่มด้านขวา เพื่อดูการเปลี่ยนแปลงของ Class

หลักการทำงาน:
  1. HTML: มีปุ่มที่ผูก onclick="toggleDarkMode()" เอาไว้
  2. CSS: เราเตรียม Class ชื่อ .dark-mode-theme ไว้ (เปลี่ยนสีพื้นหลัง/ตัวอักษร)
  3. JS: ใช้คำสั่ง classList.toggle() เพื่อสลับ Class นั้นใส่ในการ์ด (มีก็เอาออก/ไม่มีก็ใส่เพิ่ม)
JS
function toggleDarkMode() {
    // 1. เลือก Element เป้าหมาย (ตัวการ์ด)
    let card = document.querySelector("#exampleCard");
    
    // 2. สลับ Class (Toggle)
    // ถ้ามี class 'dark-mode-theme' -> เอาออก
    // ถ้าไม่มี -> ใส่เพิ่ม
    card.classList.toggle("dark-mode-theme");
}

Workshop: สร้างกล่องข้อความมหัศจรรย์ (Magic Box)
โจทย์:

ให้สร้างกล่องข้อความ 1 กล่อง และปุ่ม 1 ปุ่ม เมื่อกดปุ่ม ให้กล่องข้อความ เปลี่ยนรูปร่างหน้าตา (เช่น เปลี่ยนสีพื้นหลัง หรือขยายขนาด) โดยใช้การสลับ Class

1. สร้าง HTML
  • สร้าง <div> กำหนด id="box" และใส่ข้อความข้างใน
  • สร้าง <button> ใส่ข้อความ "แปลงร่าง" และกำหนด onclick
2. กำหนด CSS
  • ตกแต่ง #box ตามใจชอบ (เช่น ใส่ขอบ, สีพื้น)
  • สร้าง Class พิเศษชื่อ .active (กำหนดสีพื้นหลังใหม่ หรือ font size ใหญ่ขึ้น)
3. เขียน JS สั่งงาน
  • สร้างฟังก์ชัน
  • เขียนโค้ด JavaScript เพื่อเลือกกล่อง div ที่สร้างขึ้น
  • สั่งให้ฟังก์ชันสลับ Class การแสดงผลของกล่อง
Workshop 15 Example
Practice Mission: ร้านค้าออนไลน์
สถานการณ์:

คุณได้รับข้อมูลสินค้า (Array of Objects) จาก Backend หน้าที่ของคุณคือ สร้าง HTML ของสินค้าแต่ละชิ้น ขึ้นมาแสดงบนหน้าเว็บ และทำให้ปุ่ม 'กรองสินค้า' ใช้งานได้จริง

Requirements:
  1. Data: สร้างตัวแปร products เก็บข้อมูลสินค้า
  2. Render Function: สร้างฟังก์ชันที่รับค่า category
    • ใช้ .filter() เพื่อเลือกสินค้าตามหมวดหมู่ (ถ้าเป็น 'all' ให้เอาทั้งหมด)
    • ใช้ .map() เปลี่ยนข้อมูลเป็น HTML String (Template Literal)
    • เพิ่มโค้ด HTML ของสินค้าแต่ละชิ้นใส่ div#productContainer
  3. Style: ถ้าสินค้าไหน inStock: false ให้เปลี่ยนสีชื่อสินค้าเป็นสีแดง มีเส้นขีดกลาง text-decoration-line-through (สามารถใช้ Ternary Operator ใน HTML String ได้)
Practice 15 Example
JS
const productsMock = [
    { name: "Apple", cat: "Fruit", price: 30, inStock: true },
    { name: "Banana", cat: "Fruit", price: 20, inStock: false },
    { name: "Mouse", cat: "Tech", price: 500, inStock: true },
    { name: "Keyboard", cat: "Tech", price: 1200, inStock: true },
    { name: "Orange", cat: "Fruit", price: 40, inStock: true }
];
HTML
<div class="p-2 bg-white border rounded d-flex justify-content-between">
    <div><span class="text-primary">Apple</span></div>
    <span class="badge bg-secondary">30.-</span>
</div>