Frontend Academy · บทเรียน

การสร้างและต่อท้ายองค์ประกอบ

ใช้ createElement, setAttribute, append และ remove เพื่อสร้างและปรับโครงสร้าง DOM แบบไดนามิก

บทเรียน 4 จาก 413 ขั้นตอน

การสร้างและต่อท้ายองค์ประกอบ เป็นบทเรียน Frontend Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Frontend Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Frontend Academy มีบทเรียนทั้งหมด 4 บทเรียน

createElement

document.createElement(tagName) สร้างองค์ประกอบใหม่ไว้ในหน่วยความจำ ซึ่งยังไม่อยู่ใน DOM จากนั้นคุณจึงกำหนดพร็อพเพอร์ตีและเพิ่มองค์ประกอบนั้นเข้าไปในโครงสร้างต้นไม้

const btn = document.createElement('button');
btn.textContent = 'Click Me';
btn.classList.add('btn-primary');
btn.setAttribute('type', 'button');
// btn is in memory, not yet in the page

append และ appendChild

parent.append(child) เพิ่มโหนดหรือสตริงต่อท้ายองค์ประกอบลูกของ parent appendChild เป็นรูปแบบเก่าที่เทียบเท่ากัน แต่ append ยืดหยุ่นกว่า เพราะรับโหนดและสตริงได้หลายรายการ

const list = document.querySelector('ul');
const item = document.createElement('li');
item.textContent = 'New item';
list.append(item); // adds to end of list

prepend, before, after

parent.prepend() เพิ่มที่จุดเริ่มต้น ส่วน element.before() จะแทรกก่อนองค์ประกอบ และ element.after() จะแทรกหลังองค์ประกอบนั้น

const header = document.querySelector('.card-header');
const icon = document.createElement('img');
icon.src = 'icon.svg';
header.prepend(icon); // icon goes before all other children

const divider = document.createElement('hr');
header.after(divider); // divider goes after the header

insertAdjacentHTML

element.insertAdjacentHTML(position, htmlString) จะแทรก HTML ณ ตำแหน่งที่ระบุโดยไม่แทนที่เนื้อหาเดิม ตำแหน่งที่ใช้ได้ ได้แก่ 'beforebegin', 'afterbegin', 'beforeend' และ 'afterend'

const container = document.querySelector('.list');
container.insertAdjacentHTML('beforeend', `
  <li class="item">
    <span class="name">Alice</span>
  </li>
`);
// Still avoid with user input — XSS risk

cloneNode

element.cloneNode(true) จะสร้างสำเนาแบบลึกขององค์ประกอบ รวมถึงองค์ประกอบลูกทั้งหมด ส่ง false เพื่อสร้างสำเนาแบบตื้น เหมาะสำหรับการทำซ้ำองค์ประกอบ template

const template = document.querySelector('.card-template');
const clone = template.cloneNode(true);
clone.querySelector('.card-title').textContent = 'New Card';
container.append(clone);

removeChild และ remove()

element.remove() จะนำองค์ประกอบออกจาก DOM ส่วน parent.removeChild(child) แบบเก่าก็ยังใช้ได้ องค์ประกอบที่นำออกแล้วสามารถยังถูกอ้างอิงในตัวแปรและนำกลับมาแทรกใหม่ได้

const item = document.querySelector('.to-delete');
item.remove(); // clean modern syntax

replaceWith

oldElement.replaceWith(newElement) จะแทนที่องค์ประกอบเดิมใน DOM ด้วยองค์ประกอบใหม่ สะดวกกว่ารูปแบบ replaceChild แบบเก่า

const old = document.querySelector('.old-banner');
const fresh = document.createElement('div');
fresh.className = 'new-banner';
fresh.textContent = 'Updated!';
old.replaceWith(fresh);

DocumentFragment สำหรับการแทรกเป็นชุด

DocumentFragment คือ container น้ำหนักเบาที่ไม่มีอยู่ใน DOM ให้สร้างโครงสร้างย่อยภายใน แล้วจึง append ด้วยการดำเนินการครั้งเดียว วิธีนี้ทำให้เกิดการจัดวางใหม่เพียงครั้งเดียวแทนที่จะเป็น N ครั้ง

const fragment = document.createDocumentFragment();
users.forEach(user => {
  const li = document.createElement('li');
  li.textContent = user.name;
  fragment.append(li);
});
// One DOM write:
document.querySelector('ul').append(fragment);

องค์ประกอบ &lt;template&gt;

องค์ประกอบ HTML <template> ใช้เก็บมาร์กอัปที่ยังไม่แสดงผลจนกว่าจะ clone ด้วย JavaScript เหมาะกว่าการสร้างสตริงหรือ clone องค์ประกอบที่มองเห็นได้

<template id="card-tpl">
  <div class="card">
    <h3 class="card-title"></h3>
    <p class="card-body"></p>
  </div>
</template>

การตั้งค่าคุณสมบัติกับแอตทริบิวต์

คุณสมบัติขององค์ประกอบ (el.href, el.src, el.value) มักเป็นวิธีที่ตรงไปตรงมาและมีประสิทธิภาพสูงสุดในการกำหนดค่า ส่วนแอตทริบิวต์ (setAttribute) เหมาะที่สุดสำหรับแอตทริบิวต์แบบกำหนดเองหรือแอตทริบิวต์ ARIA ที่ไม่มีคุณสมบัติ DOM ที่สอดคล้องกัน

// Property (preferred for standard HTML attributes):
img.src = '/photo.webp';
link.href = '/about';

// setAttribute (for ARIA and custom attributes):
button.setAttribute('aria-expanded', 'true');
div.setAttribute('data-index', '3');

การหลีกเลี่ยง innerHTML เมื่อใช้เนื้อหาจากผู้ใช้

เมื่อสร้างองค์ประกอบจากข้อมูลที่ผู้ใช้ให้มา ควรใช้เมธอด DOM (createElement, textContent, setAttribute) แทนการสร้างสตริง HTML แล้วใช้ innerHTML ห้ามแทรก input ของผู้ใช้ลงในสตริง HTML โดยตรง

// DANGEROUS:
container.innerHTML = `<p>${userComment}</p>`;

// SAFE:
const p = document.createElement('p');
p.textContent = userComment;
container.append(p);

ตรวจสอบความเข้าใจ

คุณต้องเพิ่มรายการ 100 รายการลงใน <ul> โดยไม่ทำให้เกิดการจัดวางใหม่ 100 ครั้ง ควรใช้แนวทางใด

สรุป: การสร้างองค์ประกอบ DOM

createElement สร้างองค์ประกอบในหน่วยความจำ ส่วน append/prepend/before/after ใช้แทรกองค์ประกอบลงในโครงสร้าง remove() ใช้ลบองค์ประกอบ DocumentFragment ช่วยรวมการแทรกหลายรายการเพื่อประสิทธิภาพ องค์ประกอบ