วันพุธที่ 6 มีนาคม พ.ศ. 2562

(Back to Basic) ทำความรู้จักกับ DOM เรื่องที่นักพัฒนาเว็บควรรู้


          สวัสดีปีใหม่ย้อนหลังจ้า ถึงจะผ่านมาถึงเดือนมีนาคมแล้ว แต่สำหรับบล็อกที่หายไปนานก็ถือว่าเป็นการสวัสดีปีใหม่เป็นครั้งแรกล่ะนะ หลังจากวางมือไปนาน ก็จะไม่พูดพร่ำทำเพลงอะไรมาก มาเข้าเรื่องกันเลยดีกว่า..... สำหรับบทความแรกของปีนี้เกี่ยวข้องกับความรู้ที่นักพัฒนาเว็บควรรู้ ซึ่งเป็นพื้นฐานในการเริ่มต้นของการเขียนเว็บ นั่นก็คือ DOM

          DOM หรือ Document Object Model คือโครงสร้างของไฟล์ที่ทาง W3C (World Wide Web Consortium หรือองค์กรระหว่างประเทศที่ทำหน้าที่จัดระบบมาตรฐานที่ใช้งานบนเวิลด์ไวด์เว็บ) กำหนดขึ้นเป็นมาตราฐาน ซึ่งจะช่วยให้นักพัฒนาสามารถเขียนโค้ดหรือสคริปต์เพื่อเข้าถึง, เพิ่มเติม, เปลี่ยนแปลง รวมไปถึงลบเนื้อหาหรือโครงสร้างของไฟล์เอกสารประเภท HTML หรือ XML ได้

          เมื่อเว็บเบราว์เซอร์ทำการโหลดหน้าเว็บขึ้นมา เบราว์เซอร์ก็จะทำการสร้าง DOM ของหน้าเว็บนั้น แล้วมอง HTML Element ทั้งหมดเป็น object ที่มีโครงสร้างเป็นกิ่งก้านสาขาเหมือนต้นไม้ (ตามรูปด้านบนของบทความ) ถึงตรงนี้เพื่อน ๆ อาจจะยังงง ๆ อยู่ งั้นมาดูตัวอย่างกันเลยดีกว่า

<html>
 <head> 
  <title>Web Title</title>
 </head>
  
 <body>
  <a href="test.html">Google</a>
  <div>
   <span>Home</span>
  </div>
 </body>
  
</html>
          จากตัวอย่างโค้ดด้านบน เมื่อนำมาแปลงให้อยู่ในรูปแบบโครงสร้าง DOM ก็จะมีหน้าตาดังนี้


          จากรูปจะเห็นได้ว่า HTML DOM มีโครงสร้างเป็นลำดับชั้นเหมือนกับต้นไม้ที่แผ่กิ่งก้านสาขา โดยเริ่มต้นจาก <html> เป็นจุดเริ่มต้น ภายใน <html> ก็จะมี element ลูกเป็น <head> และ <body> ซึ่งเจ้า 2 Element นี้ก็จะมี Element ลูกไล่ระดับชั้นลึกเข้าไปเรื่อย ๆ โดยที่แต่ละ Element จะสามารถมี Element ลูกได้มากกว่า 1 Element (ตัวอย่างเช่น <html> ไง ที่มี Element ลูกมากกว่าหนึ่ง)


การจัดการ Object ภายใน DOM

          ตามมาตรฐานของ W3C อนุญาตให้เราสามารถเขียนสคริปต์เพื่อจัดการ Object ต่าง ๆ ที่อยู่ภายใน DOM ได้ ไม่ว่าจะเป็นการเพิ่มเติม การปรับเปลี่ยนแก้ไข หรือแม้แต่การลบ Element ก็สามารถทำได้แบบ Dynamic ซึ่งผลจากการแก้ไขก็จะแสดงให้เห็นบนเบราว์เซอร์ทันที

          เพื่อให้เห็นภาพ เรามาลองลงโค้ดจริงกันเลยดีกว่า โดยเราจะใช้ Javascript ในการเข้าถึงและจัดการ HTML DOM ซึ่งอันดับแรกให้เริ่มจากเขียนโค้ด HTML ธรรมดา ๆ เตรียมไว้ก่อน

<html>
 <head> 
  <title>Web Title</title>
 </head>
  
 <body id="app">
  <div id="myDiv"></div>
  
  <ul id="myList">
   <li class="item">1</li>
   <li class="item">2</li>
   <li class="item">3</li>
   <li class="item">4</li>
   <li class="item">5</li>
  </ul>
  
  <button id="deleteButton">Delete</button> | <button id="insertButton">Insert</button>
  
  
  <script>
   // พื้นที่สำหรับใส่โค้ด Javascript
  </script>
 </body>
  
</html>
          เมื่อเซฟโค้ด HTML ข้างบนเป็นไฟล์ index.html แล้วนำไปเปิดบนเบราว์เซอร์ เพื่อน ๆ ก็จะเห็นลิสต์ตัวเลข 1 ถึง 5 และมีปุ่มกดอยู่ข้างล่าง ซึ่งเมื่อกดปุ่มก็ไม่มีอะไรเกิดขึ้น ต่อไปให้เราจะทำการเพิ่มโค้ด Javascript ดังต่อไปนี้ลงในภายใน <script> แล้วทำการเซฟไฟล์

let myDiv = document.getElementById('myDiv');
myDiv.innerHTML = 'Hello my world!!';
          กด F5 เพื่อ refresh หน้าเว็บแล้วมาดูกันว่าเจ้าโค้ด 2 บรรทัดนี้ก่อให้เกิดอะไรบ้าง.....
ผลลัพธ์ที่ได้ก็คือ มีข้อความ "Hello my world!!" ปรากฏอยู่เหนือลิสต์ตัวเลขนั่นเอง

          เอาล่ะ เรามาดูคำสั่งของโค้ดที่ได้เพิ่มลงไปกัน คำสั่ง document.getElementById(id) ในบรรทัดแรกเป็นการอ้างถึง Element ที่มี attribute id เท่ากับ "myDiv" ในไฟล์ แล้วนำมาเก็บอยู่ในตัวแปรที่ชื่อว่า myDiv และในบรรทัดที่สองก็เป็นการเปลี่ยนแปลงเนื้อหาหรือส่วน text ของ Element ในตัวแปรที่เราได้เก็บไว้จากค่าว่างให้กลายเป็น "Hello my world!!" แทน แต่ข้อจำกัดของคำสั่ง document.getElementById(id) คือการอ้างอิงถึง Element ได้เพียงตัวเดียว (เนื่องจากใน HTML จะใช้ชื่อ id ซ้ำกันไม่ได้ แต่สามารถใช้ชื่อ class ซ้ำกันได้) ถัดไปให้เพื่อน ๆ ลองพิมพ์โค้ดดังต่อไปนี้

let listItem = document.getElementsByClassName('item');
listItem[0].innerHTML = listItem.length + ' items';
listItem[1].style['color'] = '#FF0000';
listItem[2].style['background-color'] = '#FF0000';
          เนื่องจากคำสั่ง document.getElementById(id) จะอ้างอิงถึง Element ได้เพียงตัวเดียว ถ้าเราต้องการอ้างถึง Element ครั้งละหลาย ๆ ตัวก็จำเป็นต้องเปลี่ยนไปใช้คำสั่ง document.getElementsByClassName(class name) หรือคำสั่ง document.getElementsByTagName(tag name) แทน ซึ่งจะคืนค่ากลับมาเป็นอาเรย์

          นอกจากเราจะเข้าถึง Element เพื่อแก้ไขแล้ว เราสามารถกำหนดให้มีการดักจับเหตุการณ์ให้กับ Element ได้อีกด้วย ตัวอย่างเช่น กำหนดให้มีการดักจับเหตุการณ์ "คลิก" เมื่อมีการคลิกปุ่มก็จะทำงานตามที่เราต้องการ

let deleteButton= document.getElementById('deleteButton');
deleteButton.addEventListener('click', function() {
 alert('Click delete button!!!');
 let app = document.getElementById('app');
 let myDiv = document.getElementById('myDiv');
 app.removeChild(myDiv);
});
         จากโค้ดข้างบน เป็นการกำหนดให้ปุ่มทำการแจ้งเตือนและลบ Element ออกเมื่อเกิดเหตุการณ์ "คลิก" ซึ่งคำสั่ง element.addEventListener('event', function) จะเป็นการกำหนดการดักจับเหตุการณ์ให้กับ Element โดย 'event' เป็นตัวกำหนดเหตุการณ์ที่จะดักจับ (ซึ่งในโค้ดตัวอย่างจะใช้เป็น 'click' ดักจับการคลิก) และ function เป็นการทำงานที่จะถูกเรียกใช้เมื่อเกิดเหตุการณ์ตามที่กำหนดไว้

          หลักการในการลบ Element นั้น เราจำเป็นต้องรู้ก่อนว่า Element นั้นอยู่ภายใต้ Element ตัวไหน ให้เราทำการอ้างอิงไปถึง Element ที่ครอบ Element ตัวนั้นก่อน จากนั้นจึงใช้คำสั่ง element.removeChild(element) เพื่อทำการลบ Element ตัวนั้น (อธิบายง่าย ๆ ก็คือ ถ้าต้องการลบ Element ตัวไหน ให้หา Element พ่อให้เจอ แล้วให้ Element พ่อสั่งลบ) จากโค้ดตัวอย่าง ขั้นตอนแรกที่ต้องทำคือการอ้างอิงถึง Element body (ซึ่งครอบ Element ที่ต้องการลบอยู่) ก่อน แล้วจึงใช้คำสั่งเพื่อลบ Element ที่มี id เท่ากับ "myDiv" ออก

let insertButton = document.getElementById('insertButton');
insertButton.addEventListener('click', function() {
 alert('Click insert button!!!');
 let newItem = document.createElement("li");
 let text = document.createTextNode("new li item");
 newItem.appendChild(text);

 let myList = document.getElementById("myList");
 myList.appendChild(newItem);
});
          ถัดจากการลบ Element แล้ว เราก็มาดูเหตุการณ์เพิ่ม Element กันบ้าง ซึ่งก็ใช้หลักการเดียวกันกับการลบ Element นั่นคือ เราจะต้องอ้างอิงไปที่ Element พ่อก่อน แล้วสั่งให้ Element พ่อทำการเพิ่ม Element ลูก โดยเราสามารถสร้าง Element ลูกด้วยคำสั่ง document.createElement(element tag) เพื่อสร้าง HTML Tag และคำสั่ง document.createTextNode(text) เพื่อสร้างข้อความที่อยู่ใน HTML Tag นั้น แล้วจึงค่อยใช้คำสั่ง element.appendChild(element) เพื่อเพิ่ม Element เข้าไปในอีก Element หนึ่ง

          ถึงตรงนี้ ผมหวังว่าเพื่อน ๆ น่าจะพอเห็นภาพและเข้าใจ DOM กันมากขึ้นแล้ว ซึ่งหลักการในบทความนี้จะเป็นพื้นฐานที่ใช้ต่อยอดในการใช้งาน Framework ตัวอื่น ๆ ที่ช่วยให้เราสามารถพัฒนาเว็บง่ายขึ้น และเพื่อน ๆ ก็จะสามารถเพิ่มลูกเล่นหรือการเคลื่อนไหวเพื่อเพิ่มความน่าสนใจให้กับเว็บไซต์ได้


ไฟล์โค้ด: AiNoTsubasa's Github