ข้ามไปยังเนื้อหา

Attributes, Properties & Events

Custom element ทุกตัวมีสองช่องทางสำหรับรับข้อมูลและหนึ่งช่องทางสำหรับส่งข้อมูลออก Attributes เข้ามาในรูปแบบ string ผ่าน HTML markup Properties เข้ามาในรูปแบบ JavaScript value ที่กำหนดโดยโค้ด ส่วน Events พาข้อมูลออกสู่ส่วนอื่นของ application การเข้าใจว่าควรใช้ช่องทางไหน — และเมื่อใด — คือกุญแจสำคัญในการเขียน custom elements ที่ทำงานได้เป็นธรรมชาติและผสานกับ framework ใดก็ได้หรือ JavaScript ล้วน

โมดูลนี้ครอบคลุมห้าบทเรียน:

  • index — ภาพรวม attributes vs properties vs events (หน้านี้)
  • reflecting-attributes — การซิงก์ attributes และ properties ให้ตรงกัน
  • properties-vs-attributes — เมื่อไหร่ควรใช้อะไร และข้อควรระวังเรื่อง type-coercion
  • custom-events — การ dispatch และ listen CustomEvent
  • composed-events — การข้าม shadow-DOM boundary ด้วย composed: true
flowchart LR
  HTML["HTML Markup"] -->|attributes| CE["Custom Element"]
  JS["JavaScript"] -->|properties| CE
  CE -->|events| App["App / Parent"]
กระแสข้อมูลเข้าและออกจาก Custom Element
ช่องทางทิศทางประเภทข้อมูลกำหนดจาก
Attributeเข้าstringHTML หรือ setAttribute()
Propertyเข้าJS value ใดก็ได้การ assign ใน JavaScript
EventออกEvent / CustomEventdispatchEvent() ภายใน element

Attributes คือ interface ตามธรรมชาติจาก HTML — เป็นสิ่งที่เราเขียนใน markup และ HTML parser เข้าใจได้ Properties คือ JavaScript interface — รองรับ type ใดก็ได้: ตัวเลข, boolean, array, object ส่วน Events คือวิธีเดียวที่ถูกต้องสำหรับ element ในการสื่อสารออกไปภายนอก ซึ่งทำให้ element แยกออกจากผู้ใช้งานอย่างสมบูรณ์

เมื่อ browser แปลง <attr-demo label="42"> ค่า "42" คือ string หาก element ต้องการตัวเลข โค้ดของคุณต้องแปลงค่าเอง นี่คือสาเหตุที่พบบ่อยที่สุดของบัก subtle เมื่อย้ายจาก framework component (ที่ props มี type ใดก็ได้) มาสู่ custom elements

class AttrDemo extends HTMLElement {
static get observedAttributes() { return ['count']; }
attributeChangedCallback(name, oldVal, newVal) {
// newVal is always a string — coerce explicitly
var count = Number(newVal);
this.textContent = 'Count: ' + count;
}
}
customElements.define('attr-demo', AttrDemo);

การกำหนด property โดยตรงใน JavaScript ช่วยให้ส่งค่าที่ซับซ้อนได้โดยไม่ต้องแปลงเป็น string:

var el = document.querySelector('my-chart');
el.data = [{ x: 1, y: 2 }, { x: 3, y: 4 }]; // object, not a string

setter ของ element จะรับค่าตามที่ส่งมา ไม่มีการแปลงเป็น string เว้นแต่คุณจะเขียนเองอย่างชัดเจน นี่คือเหตุผลที่การกำหนดค่าที่ซับซ้อน — array, object, function — ควรอยู่บน properties ไม่ใช่ attributes

Element ไม่ควรเข้าถึง DOM เพื่อแก้ไข parent โดยตรง แต่ควร dispatch event และปล่อยให้ parent ตัดสินใจว่าจะทำอะไร:

this.dispatchEvent(new CustomEvent('demo-click', {
bubbles: true,
composed: true,
detail: { label: this.getAttribute('label') }
}));

Parent ฟังด้วย addEventListener('demo-click', handler) Element และ parent แยกออกจากกันอย่างสมบูรณ์

Element ด้านล่างอ่าน attribute label และแสดงผลในกล่องที่มีสไตล์ คลิกที่กล่องเพื่อ dispatch event demo-click — หน้าเพจจะจับ event นั้นและแสดง log entry

ความแตกต่างหลักระหว่าง attribute และ property บน custom element คืออะไร?
Events ไหลไปในทิศทางใดในโมเดลข้อมูลของ custom element?
observedAttributes ใช้สำหรับอะไร?