Manipulasi DOM

Manipulasi DOM

Eksplorasi ke dalam tipe HTMLElement

Dalam 20+ tahun sejak standarisasi, JavaScript telah berkembang pesat. Meskipun pada tahun 2020, JavaScript dapat digunakan di server, dalam ilmu data, dan bahkan pada perangkat IoT, penting untuk mengingat kasus penggunaannya yang paling populer: web browser.

Situs web terdiri dari dokumen HTML dan/atau XML. Dokumen-dokumen ini statis, tidak berubah. Document Object Model (DOM) adalah antarmuka pemrograman yang diterapkan oleh browser untuk membuat situs web statis berfungsi. API DOM dapat digunakan untuk mengubah struktur dokumen, style, dan konten. API ini sangat kuat sehingga framework frontend yang tak terhitung jumlahnya (jQuery, React, Angular, dll.) telah dikembangkan di sekitarnya untuk membuat situs web dinamis lebih mudah dikembangkan.

TypeScript adalah superset dari JavaScript, dan TypeScript dilengkapi dengan definisi tipe untuk DOM API. Secara standar, definisi ini sudah tersedia dalam proyek TypeScript. Dari 20.000+ baris definisi di lib.dom.d.ts, satu yang menonjol di antara yang lain: HTMLElement. Jenis ini adalah hal penting untuk manipulasi DOM dengan TypeScript.

Anda bisa mengeksplor source code Definisi tipe DOM

Contoh Dasar

Diberikan berkas index.html yang disederhanakan:

<!DOCTYPE html>
<html lang="en">
<head><title>TypeScript Dom Manipulation</title></head>
<body>
<div id="app"></div>
<!-- Assume index.js is the compiled output of index.ts -->
<script src="index.js"></script>
</body>
</html>

Mari kita jelajahi kode TypeScript yang menambahkan elemen <p>Hello, World</p> ke elemen #app.

ts
// 1. Pilih elemen div menggunakan properti id
const app = document.getElementById("app");
// 2. Buat element <p></p> baru secara terprogram
const p = document.createElement("p");
// 3. Tambahkan konten teks
p.textContent = "Hello, World!";
// 4. Tambahkan elemen p ke elemen div
app?.appendChild(p);

Setelah menyusun dan menjalankan halaman index.html, HTML yang dihasilkan adalah:

html
<div id="app">
<p>Hello, World!</p>
</div>

Antarmuka Document

Baris pertama kode TypeScript menggunakan variabel global document. Memeriksa variabel menunjukkan bahwa ia didefinisikan oleh antarmuka Dokumen dari berkas lib.dom.d.ts. Cuplikan kode berisi panggilan ke dua method, getElementById dan createElement.

Document.getElementById

Definisi dari method ini adalah sebagai berikut:

ts
getElementById(elementId: string): HTMLElement | null;

Berikan string id elemen dan itu akan mengembalikan HTMLElement ataunull. Method ini memperkenalkan salah satu jenis terpenting, HTMLElement. Ini berfungsi sebagai antarmuka dasar untuk setiap antarmuka elemen lainnya. Misalnya, variabel p dalam contoh kode berjenis HTMLParagraphElement. Perhatikan juga bahwa method ini dapat mengembalikan null. Ini karena method tidak dapat memastikan kapan elemen itu tersedia atau apakah elemen tersebut ada atau tidak. Di baris terakhir cuplikan kode, operator optional chaining digunakan untuk memanggil appendChild.

Document.createElement

Definisi untuk metode ini adalah (definisi deprecated telah dihilangkan):

ts
createElement<K extends keyof HTMLElementTagNameMap>(tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K];
createElement(tagName: string, options?: ElementCreationOptions): HTMLElement;

Ini adalah definisi fungsi yang kelebihan beban. Kelebihan kedua adalah yang paling sederhana dan bekerja sangat mirip dengan method getElementById. Berikan setiap string dan ia akan mengembalikan standar HTMLElement. Definisi inilah yang memungkinkan developer membuat tag elemen HTML yang unik.

Misalnya document.createElement('xyz') mengembalikan elemen <xyz></xyz>, jelas bukan elemen yang ditentukan oleh spesifikasi HTML.

Jika tertarik, Anda dapat berinteraksi dengan elemen tag kustom menggunakan document.getElementsByTagName

Untuk definisi pertama dari createElement, ini menggunakan beberapa pola umum lanjutan. Paling baik dipahami jika dipecah menjadi beberapa bagian, dimulai dengan ekspresi umum: <K extends keyof HTMLElementTagNameMap>. Ekspresi ini mendefinisikan parameter umum K yang constrained ke kunci antarmukaHTMLElementTagNameMap. Antarmuka peta berisi setiap nama tag HTML yang ditentukan dan antarmuka tipe yang sesuai. Berikut adalah 5 nilai yang dipetakan pertama:

ts
interface HTMLElementTagNameMap {
"a": HTMLAnchorElement;
"abbr": HTMLElement;
"address": HTMLElement;
"applet": HTMLAppletElement;
"area": HTMLAreaElement;
...
}

Beberapa elemen tidak menunjukkan properti unik sehingga mereka hanya mengembalikan HTMLElement, tetapi tipe lain memiliki properti dan method unik sehingga mereka mengembalikan antarmuka spesifiknya (yang akan memperluas atau mengimplementasikan HTMLElement).

Sekarang, untuk sisa definisi createElement:(tagName: K, options ?: ElementCreationOptions): HTMLElementTagNameMap [K]. Argumen pertama tagName didefinisikan sebagai parameter umum K. Interpreter TypeScript cukup pintar untuk infer parameter generik dari argumen ini. Ini berarti bahwa pengembang sebenarnya tidak harus menentukan parameter umum saat menggunakan metode ini; nilai apa pun yang diteruskan ke argumen tagName akan disimpulkan sebagai K dan karenanya dapat digunakan di seluruh definisi lainnya. Itulah yang sebenarnya terjadi; nilai kembalian HTMLElementTagNameMap [K] mengambil argumen tagName dan menggunakannya untuk mengembalikan jenis yang sesuai. Definisi ini adalah bagaimana variabel p dari kode sebelumnya mendapatkan jenis HTMLParagraphElement. Dan jika kodenya adalah document.createElement ('a'), maka itu akan menjadi elemen jenis HTMLAnchorElement.

Antarmuka Node

Fungsi document.getElementById mengembalikan HTMLElement. Antarmuka HTMLElement memperluas antarmuka Element, yang memperluas antarmuka Node. Ekstensi prototipe ini memungkinkan semua HTMLElements untuk menggunakan subset method standar. Dalam cuplikan kode, kami menggunakan properti yang ditentukan pada antarmuka Node untuk menambahkan elemenp baru ke situs web.

Node.appendChild

Baris terakhir dari potongan kode adalah app?.AppendChild (p). Bagian sebelumnya, document.getElementById, merinci bahwa operator optional chaining digunakan di sini karena app berpotensi menjadi null pada waktu proses. Method appendChild didefinisikan oleh:

ts
appendChild<T extends Node>(newChild: T): T;

Method ini bekerja mirip dengan metode createElement karena parameter umum T disimpulkan dari argumen newChild. T adalah constrained ke antarmuka dasar lainNode.

Perbedaan antara children dan childNodes

Sebelumnya, dokumen ini merinci antarmuka HTMLElement yang diperluas dari Element yang diturunkan dari Node. Di DOM API ada konsep elemen children. Misalnya dalam HTML berikut, tag p adalah turunan dari elemen div

tsx
<div>
<p>Hello, World</p>
<p>TypeScript!</p>
</div>;
const div = document.getElementsByTagName("div")[0];
div.children;
// HTMLCollection(2) [p, p]
div.childNodes;
// NodeList(2) [p, p]

Setelah menangkap elemen div, prop children akan mengembalikan daftar HTMLCollection yang berisi HTMLParagraphElements. Properti childNodes akan mengembalikan daftar node NodeList yang serupa. Setiap tag p akan tetap berjenis HTMLParagraphElements, tetapi NodeList dapat berisi HTML node tambahan yang tidak bisa dilakukan oleh list HTMLCollection.

Ubah html dengan menghapus salah satu tag p, tetapi pertahankan teksnya.

tsx
<div>
<p>Hello, World</p>
TypeScript!
</div>;
const div = document.getElementsByTagName("div")[0];
div.children;
// HTMLCollection(1) [p]
div.childNodes;
// NodeList(2) [p, text]

Lihat bagaimana kedua daftar berubah. children sekarang hanya berisi elemen <p>Hello, World</p>, dan childNodes berisi simpul teks daripada dua simpul p. Bagian teks dari NodeList adalah Node literal yang berisi teks TypeScript!. List children tidak berisi Node, ini karena tidak dianggap sebagai HTMLElement.

Method querySelector dan querySelectorAll

Kedua method ini adalah tool yang hebat untuk mendapatkan daftar elemen dom yang sesuai dengan kumpulan constraint yang lebih unik. Mereka didefinisikan di lib.dom.d.ts sebagai:

ts
/**
* Mengembalikan elemen pertama yang merupakan turunan dari node yang cocok dengan selector.
*/
querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
querySelector<K extends keyof SVGElementTagNameMap>(selectors: K): SVGElementTagNameMap[K] | null;
querySelector<E extends Element = Element>(selectors: string): E | null;
/**
* Menampilkan semua turunan elemen node yang cocok dengan selector.
*/
querySelectorAll<K extends keyof HTMLElementTagNameMap>(selectors: K): NodeListOf<HTMLElementTagNameMap[K]>;
querySelectorAll<K extends keyof SVGElementTagNameMap>(selectors: K): NodeListOf<SVGElementTagNameMap[K]>;
querySelectorAll<E extends Element = Element>(selectors: string): NodeListOf<E>;

Definisi querySelectorAll mirip dengan getElementsByTagName, kecuali ia mengembalikan tipe baru: NodeListOf. Jenis kembalian ini pada dasarnya adalah implementasi khusus dari elemen daftar standar JavaScript. Bisa dibilang, mengganti NodeListOf<E> dengan E[] akan menghasilkan pengalaman pengguna yang sangat mirip. NodeListOf hanya mengimplementasikan properti dan method berikut:length, item (index),forEach ((value, key, parent) => void), dan numeric indexing. Selain itu, method ini mengembalikan daftar elements, bukan nodes, yang dikembalikan oleh NodeList dari method .childNodes. Meskipun ini mungkin tampak sebagai perbedaan, perhatikan bahwa antarmuka Element merupakan turunan dari Node.

Untuk melihat method ini beraksi, ubah kode yang ada menjadi:

tsx
<ul>
<li>First :)</li>
<li>Second!</li>
<li>Third times a charm.</li>
</ul>;
const first = document.querySelector("li"); // mengembalikan elemen li pertama
const all = document.querySelectorAll("li"); // mengembalikan daftar semua elemen li

Tertarik untuk mempelajari lebih lanjut?

Bagian terbaik tentang definisi tipe lib.dom.d.ts adalah bahwa definisi tersebut mencerminkan tipe yang dijelaskan di situs dokumentasi Mozilla Developer Network (MDN). Misalnya, antarmuka HTMLElement didokumentasikan oleh halaman HTMLElement di MDN. Halaman ini mencantumkan semua properti yang tersedia, method, dan terkadang bahkan contoh. Aspek hebat lainnya dari halaman-halaman tersebut adalah mereka menyediakan tautan ke dokumen standar yang sesuai. Berikut ini tautan ke Rekomendasi W3C untuk HTMLElement.

Sumber:

The TypeScript docs are an open source project. Help us improve these pages by sending a Pull Request

Contributors to this page:
BDPBurhanudin Dwi Prakoso  (8)
OTOrta Therox  (1)

Last updated: 23 Nov 2024