JavaScript | BAB 6 Manipulasi DOM JS
Spoiler
Manipulasi DOM JavaScript - Tutorial Lengkap dengan Contoh Praktis
1. Memahami DOM (Document Object Model)
Document Object Model (DOM) adalah interface pemrograman untuk dokumen HTML dan XML. DOM merepresentasikan halaman web sebagai struktur tree yang terdiri dari node-node.
Contoh Struktur DOM:
<!DOCTYPE html> <html> <head> <title>My title</title> </head> <body> <a href="#">My link</a> <h1>My header</h1> </body> </html>
Penjelasan:
- Elemen root adalah <html>, yang memuat elemen <head> dan <body>.
- Di dalam <head>, terdapat elemen <title> yang berisi teks "My title".
- Di dalam <body>, terdapat elemen <a> dengan atribut href, yang menampilkan teks "My link", dan elemen <h1> yang berisi teks "My header".
2. Metode Akses Elemen DOM
2.1 Mengakses dengan ID
HTML:
<div id="myBox">Ini adalah box</div> <div id="content">Ini adalah konten</div>
JavaScript:
// Mengakses elemen dengan ID let boxElement = document.getElementById("myBox"); console.log(boxElement.innerHTML); // Output: "Ini adalah box" // Mengubah konten elemen boxElement.innerHTML = "Box telah diubah"; // Mengubah style boxElement.style.backgroundColor = "yellow";
Penjelasan:
- getElementById() mengembalikan satu elemen spesifik
- Jika ID tidak ditemukan, mengembalikan null
- ID harus unik dalam satu halaman
2.2 Mengakses dengan Class Name
HTML:
<div class="item">Item 1</div> <div class="item">Item 2</div> <div class="item">Item 3</div>
JavaScript:
// Mengambil semua elemen dengan class "item" let items = document.getElementsByClassName("item"); // Iterasi melalui elements for(let i = 0; i < items.length; i++) { console.log(items[i].innerHTML); items[i].style.color = "blue"; } // Menggunakan Array.from untuk metode array Array.from(items).forEach(item => { item.addEventListener("click", function() { this.style.backgroundColor = "yellow"; }); });
Penjelasan:
- getElementsByClassName() mengembalikan HTMLCollection
- Bisa ada banyak elemen dengan class yang sama
- HTMLCollection bersifat live (otomatis update)
2.3 Query Selector
HTML:
<div class="container"> <p class="text">Paragraf 1</p> <p class="text highlight">Paragraf 2</p> <span class="text">Span text</span> </div>
JavaScript:
// Mengambil elemen pertama yang cocok let firstText = document.querySelector(".text"); console.log(firstText.innerHTML); // Output: "Paragraf 1" // Mengambil semua elemen yang cocok let allTexts = document.querySelectorAll(".text"); allTexts.forEach(text => { text.style.color = "red"; }); // Menggunakan selector yang lebih kompleks let highlightedText = document.querySelector(".text.highlight"); console.log(highlightedText.innerHTML); // Output: "Paragraf 2"
Penjelasan:
- querySelector() mengembalikan elemen pertama yang cocok
- querySelectorAll() mengembalikan NodeList dari semua elemen yang cocok
- Bisa menggunakan selector CSS kompleks
3. Manipulasi Konten dan Atribut
3.1 Mengubah Konten
HTML:
<div id="content">Konten awal</div> <div id="htmlContent">Teks <b>tebal</b></div>
JavaScript:
// Menggunakan innerText let content = document.getElementById("content"); content.innerText = "Konten baru"; // Menggunakan innerHTML let htmlContent = document.getElementById("htmlContent"); htmlContent.innerHTML = "Teks dengan <i>italic</i> dan <b>bold</b>"; // Menggunakan textContent content.textContent = "Ini adalah text content";
Perbedaan:
- innerText memperhatikan styling CSS (hidden elements)
- innerHTML bisa mengandung HTML tags
- textContent mengambil konten text mentah
3.2 Manipulasi Atribut
HTML:
<img id="myImage" src="old.jpg" alt="Gambar lama"> <a id="myLink" href="https://example.com">Link</a>
JavaScript:
// Menggunakan setAttribute let img = document.getElementById("myImage"); img.setAttribute("src", "new.jpg"); img.setAttribute("alt", "Gambar baru"); // Menggunakan properti langsung let link = document.getElementById("myLink"); link.href = "https://newexample.com"; // Mengecek atribut console.log(img.hasAttribute("alt")); // true console.log(img.getAttribute("src")); // "new.jpg" // Menghapus atribut img.removeAttribute("alt");
Penjelasan:
- setAttribute() untuk mengubah atau menambah atribut
- getAttribute() untuk mengambil nilai atribut
- removeAttribute() untuk menghapus atribut
- Properti langsung lebih mudah tapi terbatas pada atribut standar
4. Event Handling
4.1 Event Click
HTML:
<button id="myButton">Klik Saya</button> <div id="output"></div>
JavaScript:
let button = document.getElementById("myButton"); let output = document.getElementById("output"); // Cara 1: addEventListener button.addEventListener("click", function(event) { output.textContent = "Button diklik!"; console.log(event); // melihat object event }); // Cara 2: onclick property button.onclick = function() { output.textContent = "Button diklik (via onclick)!"; }; // Event dengan parameter button.addEventListener("click", function(event) { // Menghentikan default action event.preventDefault(); // Mendapatkan informasi event console.log(event.type); // "click" console.log(event.target); // element yang diklik });
Penjelasan:
- addEventListener lebih fleksibel, bisa multiple handlers
- onclick lebih sederhana tapi hanya satu handler
- event object memberikan informasi tambahan tentang event
4.2 Form Events
HTML:
<form id="myForm"> <input type="text" id="myInput" placeholder="Ketik sesuatu..."> <button type="submit">Submit</button> </form> <div id="formOutput"></div>
JavaScript:
let form = document.getElementById("myForm"); let input = document.getElementById("myInput"); let formOutput = document.getElementById("formOutput"); // Form submit event form.addEventListener("submit", function(event) { event.preventDefault(); // Mencegah form submit default formOutput.textContent = `Form disubmit dengan nilai: ${input.value}`; }); // Input events input.addEventListener("input", function(event) { formOutput.textContent = `Sedang mengetik: ${this.value}`; }); input.addEventListener("focus", function() { this.style.backgroundColor = "lightyellow"; }); input.addEventListener("blur", function() { this.style.backgroundColor = ""; });
Penjelasan:
- preventDefault() mencegah halaman refresh saat submit
- input event terjadi setiap kali nilai berubah
- focus dan blur untuk styling interaktif
5. Contoh Aplikasi Praktis: Dynamic Todo List
HTML:
<div class="todo-app"> <h2>Todo List</h2> <form id="todoForm"> <input type="text" id="todoInput" placeholder="Tambah tugas baru..."> <button type="submit">Tambah</button> </form> <ul id="todoList"></ul> <div id="todoStats"></div> </div>
CSS:
.todo-app { max-width: 500px; margin: 20px auto; padding: 20px; border: 1px solid #ddd; } .completed { text-decoration: line-through; color: #888; } .todo-item { display: flex; justify-content: space-between; align-items: center; padding: 8px; margin: 4px 0; background-color: #f9f9f9; }
JavaScript:
// Lanjutan JavaScript untuk Todo App class TodoApp { constructor() { this.form = document.getElementById("todoForm"); this.input = document.getElementById("todoInput"); this.list = document.getElementById("todoList"); this.stats = document.getElementById("todoStats"); this.todos = []; this.setupEventListeners(); this.updateStats(); } setupEventListeners() { // Handle form submission this.form.addEventListener("submit", (e) => { e.preventDefault(); this.addTodo(); }); // Handle item interactions using event delegation this.list.addEventListener("click", (e) => { const item = e.target.closest(".todo-item"); if (!item) return; if (e.target.classList.contains("delete-btn")) { this.deleteTodo(item); } else if (e.target.classList.contains("toggle-btn")) { this.toggleTodo(item); } }); } addTodo() { const text = this.input.value.trim(); if (!text) return; const todo = { id: Date.now(), text: text, completed: false }; this.todos.push(todo); this.renderTodo(todo); this.input.value = ""; this.updateStats(); } renderTodo(todo) { const li = document.createElement("li"); li.className = "todo-item"; li.dataset.id = todo.id; li.innerHTML = `${todo.text}`; this.list.appendChild(li); } deleteTodo(item) { const id = parseInt(item.dataset.id); this.todos = this.todos.filter(todo => todo.id !== id); item.remove(); this.updateStats(); } toggleTodo(item) { const id = parseInt(item.dataset.id); const todo = this.todos.find(t => t.id === id); if (!todo) return; todo.completed = !todo.completed; const todoText = item.querySelector(".todo-text"); todoText.classList.toggle("completed"); this.updateStats(); } updateStats() { const total = this.todos.length; const completed = this.todos.filter(todo => todo.completed).length; const pending = total - completed; this.stats.innerHTML = `Total: ${total} | Selesai: ${completed} | Pending: ${pending}
`; } } // Inisialisasi aplikasi const todoApp = new TodoApp();
Penjelasan Komprehensif:
- Struktur Kelas
- Menggunakan pendekatan OOP untuk organisasi kode yang lebih baik
- Semua fungsionalitas terkait todo list dienkapsulasi dalam satu kelas
- State (todos) dikelola secara terpusat
- Event Handling
- Menggunakan event delegation untuk efisiensi
- Penanganan berbagai jenis interaksi (tambah, hapus, toggle)
- Validasi input sederhana
- Manipulasi DOM
- Pembuatan elemen dinamis
- Update UI berdasarkan state
- Penggunaan template literals untuk HTML
6. Praktik Terbaik dalam Manipulasi DOM
6.1 Performa
Contoh Buruk:
// Manipulasi DOM dalam loop (buruk) for(let i = 0; i < 1000; i++) { document.body.innerHTML += `Item ${i}`; }
Contoh Baik:
// Menggunakan DocumentFragment (baik) const fragment = document.createDocumentFragment(); for(let i = 0; i < 1000; i++) { const div = document.createElement('div'); div.textContent = `Item ${i}`; fragment.appendChild(div); } document.body.appendChild(fragment);
Penjelasan:
- Gunakan DocumentFragment untuk batch updates
- Minimalisir reflow dan repaint
- Hindari manipulasi DOM berulang
6.2 Event Delegation
HTML:
<ul id="itemList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul>
Contoh Buruk:
// Menambahkan event listener ke setiap item (buruk) document.querySelectorAll('#itemList li').forEach(item => { item.addEventListener('click', function() { this.style.color = 'red'; }); });
Contoh Baik:
// Menggunakan event delegation (baik) document.getElementById('itemList').addEventListener('click', function(e) { if (e.target.tagName === 'LI') { e.target.style.color = 'red'; } });
Keuntungan Event Delegation:
- Lebih efisien untuk memori
- Otomatis bekerja untuk elemen dinamis
- Kode lebih mudah dikelola
6.3 Keamanan
Hindari:
// JANGAN LAKUKAN INI! element.innerHTML = userInput; // Berbahaya - XSS risk
Lakukan:
// Sanitasi input function sanitizeInput(input) { const div = document.createElement('div'); div.textContent = input; return div.innerHTML; } // Penggunaan yang aman element.textContent = userInput; // atau element.innerHTML = sanitizeInput(userInput);
Tips Keamanan:
- Selalu sanitasi input pengguna
- Gunakan textContent untuk konten plain text
- Validasi input sebelum memasukkan ke DOM
7. Debugging DOM
// Console methods untuk debugging console.log(element); // Melihat elemen console.dir(element); // Melihat properti elemen console.table(nodeList); // Melihat collection dalam format tabel // Debugging event listeners function handleClick(e) { console.log('Event:', e); console.log('Target:', e.target); console.log('Current Target:', e.currentTarget); console.trace(); // Melihat stack trace } element.addEventListener('click', handleClick);
Tools Debugging:
- Chrome DevTools Elements panel
- Event Listeners tab
- Breakpoints untuk manipulasi DOM