DOM និង Event
មាតិកា
- DOM ជាដើមឈើដែលអ្នកអាចកែបាន
- ការស្វែងរក Element
- ការផ្លាស់ប្តូរអត្ថបទដោយសុវត្ថិភាព
- ការបង្កើត និងបន្ថែម Element
- Class និង Data Attribute
- Event
- Event Delegation៖ បញ្ជី Project ដែលអាចត្រងបាន
- Form និង preventDefault
- ប៊ូតុង Dark Mode ជាមួយ localStorage
- សាកល្បងដោយខ្លួនឯង
1. DOM ជាដើមឈើដែលអ្នកអាចកែបាន
នៅក្នុង Inside the Browser និងម្តងទៀតក្នុងស៊េរី HTML អ្នកបានឃើញថា browser បំប្លែងអត្ថបទ HTML ទៅជាដើមឈើនៃ element ហៅថា DOM (Document Object Model)។ រហូតមកដល់ពេលនេះ អ្នកគ្រាន់តែមើលដើមឈើនោះក្នុង DevTools។ JavaScript ក៏អាច អាន និងកែប្រែវា បានដែរ ហើយ browser គូរទំព័រឡើងវិញភ្លាមៗ។
object ពីរចាប់ផ្តើមអ្វីៗទាំងអស់៖
documentគឺជាទំព័រទាំងមូល។document.bodyគឺជា element<body>។- រាល់ element គឺជា object។ វាមាន property ដូចជា
textContentនិង method ដូចជាappend។
នេះជាមូលហេតុដែល DOM សំខាន់៖ វាជារបៀបដែលទំព័រឋិតិវន្តក្លាយជាទំព័រអន្តរកម្ម។ អ្នកនឹងត្រូវបើក index.html ជាមួយ Live Server ដោយមាន module script ត្រូវបានផ្ទុកដូចជំពូកមុន៖
<script type="module" src="js/main.js"></script>
2. ការស្វែងរក Element
ដើម្បីផ្លាស់ប្តូរ element អ្នកត្រូវរកវាជាមុនសិន។ ប្រើ CSS selector ដូចគ្នាពីជំពូក stylesheet៖
const title = document.querySelector("h1");
const cards = document.querySelectorAll(".project-card");
| Method | ត្រឡប់ |
|---|---|
querySelector(selector) | ការ match ដំបូងគេ ឬ null ប្រសិនបើគ្មានអ្វី match |
querySelectorAll(selector) | បញ្ជីនៃការ match ទាំងអស់ (ទទេ ប្រសិនបើគ្មាន) |
បញ្ជីពី querySelectorAll ប្រើជាមួយ for...of បាន ហើយអ្នកក៏អាចបំប្លែងវាទៅជា array ពិតប្រាកដដោយ [...cards]។
for (const card of cards) {
console.log(card.textContent);
}
ប្រសិនបើ selector មិន match អ្វីទេ querySelector ផ្តល់ null ដល់អ្នក ហើយការប្រើវាបណ្តាលឲ្យមាន error Cannot read properties of null។ នៅពេលអ្នកឃើញវា សូមពិនិត្យមើលថាតើ selector សរសេរខុសឬទេ ឬ script ដំណើរការមុនពេល element មាន។
3. ការផ្លាស់ប្តូរអត្ថបទដោយសុវត្ថិភាព
property ពីរផ្លាស់ប្តូរអ្វីដែល element មាន៖
title.textContent = "Hello, I'm Dara"; // អត្ថបទធម្មតា
title.innerHTML = "Hello, <em>Dara</em>"; // ត្រូវបាន parse ជា HTML
textContent ចាត់ទុកអ្វីៗទាំងអស់ជាអត្ថបទ។ innerHTML ចាត់ទុកវាជា HTML ដូច្នេះ tag ក្លាយជា element ពិតប្រាកដ។
ការព្រមាន។ កុំដាក់អត្ថបទពីអ្នកប្រើ ពី URL ឬពី API ចូលក្នុង innerHTML ដាច់ខាត។ ប្រសិនបើនរណាម្នាក់វាយ <img src=x onerror="alert('hacked')"> ហើយអ្នកបញ្ចូលវាដោយ innerHTML browser នឹងដំណើរការកូដនោះ។ ការវាយប្រហារនេះហៅថា XSS (cross-site scripting) ហើយវាអាចលួចទិន្នន័យពីអ្នកទស្សនាផ្សេងទៀត។ ច្បាប់សុវត្ថិភាពគឺ៖
ប្រើ
textContentសម្រាប់អត្ថបទណាដែលអ្នកមិនបានសរសេរដោយខ្លួនឯង។
ប្រើ innerHTML តែជាមួយ string ថេរដែលអ្នកសរសេរក្នុងកូដរបស់អ្នកផ្ទាល់ប៉ុណ្ណោះ ហើយទោះជាបែបនោះក៏ដោយ សូមពេញចិត្តផ្នែកបន្ទាប់ជាង។
4. ការបង្កើត និងបន្ថែម Element
ដើម្បីសាងសង់ element ថ្មី សូមបង្កើតវា បំពេញវា រួចបន្ថែមវាទៅទំព័រ៖
const card = document.createElement("article");
card.className = "project-card";
const heading = document.createElement("h3");
heading.textContent = "Budget Tracker";
card.append(heading);
document.querySelector("#project-list").append(card);
append បន្ថែមទៅចុងនៃ parent។ វាទទួលបានច្រើនធាតុ និង string ធម្មតា។ method មានប្រយោជន៍ផ្សេងទៀត៖ prepend (បន្ថែមនៅដើម), remove() (លុប element) និង replaceChildren() (ធ្វើឲ្យ parent ទទេ ឬជំនួសកូនទាំងអស់ក្នុងពេលតែមួយ)។
ដោយសារ element ថ្មីត្រូវបានសាងសង់ពី createElement និង textContent គ្មានអត្ថបទណាត្រូវបានចាត់ទុកជា HTML ទេ ដូច្នេះវាមានសុវត្ថិភាព សូម្បីតែសម្រាប់ទិន្នន័យដែលអ្នកគ្រប់គ្រងមិនបាន។
5. Class និង Data Attribute
ជំនួសឲ្យការកំណត់ពណ៌ពី JavaScript សូមផ្លាស់ប្តូរ class ហើយទុកឲ្យ CSS ធ្វើការតុបតែង។ រក្សាទម្រង់រូបរាងក្នុង CSS និងអាកប្បកិរិយាក្នុង JavaScript៖
card.classList.add("featured");
card.classList.remove("featured");
card.classList.toggle("featured"); // បន្ថែមបើគ្មាន លុបបើមាន
card.classList.contains("featured"); // true ឬ false
element HTML ក៏អាចផ្ទុកទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកក្នុង attribute data- ដែល JavaScript អានតាមរយៈ dataset៖
<button data-filter="javascript">JavaScript</button>
const button = document.querySelector("button");
console.log(button.dataset.filter); // "javascript"
ឈ្មោះដូចជា data-project-id ក្លាយជា dataset.projectId៖ សញ្ញាដាច់ (-) ត្រូវបានប្តូរទៅជា camelCase។ value ទាំងអស់ជា string។
6. Event
event គឺជាអ្វីមួយដែលកើតឡើង៖ ការ click ការចុចគ្រាប់ចុច ការ submit form។ អ្នកឆ្លើយតបដោយ addEventListener ដោយផ្តល់ឈ្មោះ event និង function ដែលត្រូវហៅ៖
const themeButton = document.querySelector("#theme-toggle");
themeButton.addEventListener("click", () => {
console.log("Clicked!");
});
browser ហៅ function របស់អ្នក ហើយបញ្ជូន event object ដែលមានព័ត៌មានលម្អិតទៅវា៖
| Property | អត្ថន័យ |
|---|---|
event.type | ឈ្មោះ event ឧទាហរណ៍ "click" |
event.target | element ដែលត្រូវបាន click ពិតប្រាកដ |
event.currentTarget | element ដែល listener ត្រូវបានភ្ជាប់ |
event.key | សម្រាប់ event ក្តារចុច គឺគ្រាប់ចុចដែលបានចុច |
event.preventDefault() | បញ្ឈប់សកម្មភាពលំនាំដើមរបស់ browser |
event ទូទៅ៖ click, input (ការវាយក្នុង field), submit, keydown, change។
7. Event Delegation៖ បញ្ជី Project ដែលអាចត្រងបាន
ឥឡូវសាងសង់ feature ដំបូង។ ក្នុង index.html បន្ថែមប៊ូតុងត្រង និងបញ្ជីទទេ៖
<section id="projects">
<h2>Projects</h2>
<div id="filters">
<button type="button" data-filter="all">All</button>
<button type="button" data-filter="html">HTML</button>
<button type="button" data-filter="css">CSS</button>
<button type="button" data-filter="javascript">JavaScript</button>
</div>
<div id="project-list"></div>
</section>
ក្នុង js/main.js import ទិន្នន័យពីជំពូកមុន ហើយគូរបញ្ជី៖
import { projects } from "./projects.js";
import { filterByTag } from "./helpers.js";
const filters = document.querySelector("#filters");
const list = document.querySelector("#project-list");
function createCard(project) {
const card = document.createElement("article");
card.className = "project-card";
const heading = document.createElement("h3");
heading.textContent = project.title;
const details = document.createElement("p");
details.textContent = `${project.year} · ${project.tags.join(", ")}`;
card.append(heading, details);
return card;
}
function render(items) {
list.replaceChildren(...items.map(createCard));
}
render(projects);
ដើម្បីឆ្លើយតបនឹងការ click អ្នកអាចបន្ថែម listener ទៅប៊ូតុងនីមួយៗ។ គំរូល្អជាងគឺ event delegation៖ បន្ថែម listener តែមួយ លើ parent។ ការ click លើកូនៗ bubble ឡើងលើ ទៅវា ហើយ event.target ប្រាប់អ្នកថាកូនមួយណាត្រូវបាន click។
filters.addEventListener("click", (event) => {
const button = event.target.closest("button[data-filter]");
if (button === null) return;
const tag = button.dataset.filter;
render(tag === "all" ? projects : filterByTag(projects, tag));
});
closest ដើរឡើងលើពី element ដែលត្រូវបាន click ទៅរក match ជិតបំផុត ហើយត្រឡប់ null ប្រសិនបើការ click មិនមែនលើប៊ូតុងត្រង។ delegation មានអត្ថប្រយោជន៍ពិតប្រាកដ៖ ប្រសិនបើអ្នកបន្ថែមប៊ូតុងច្រើនទៀតនៅពេលក្រោយ ឬបង្កើតវាដោយ JavaScript វាដំណើរការដោយមិនត្រូវការកូដបន្ថែមទេ។
8. Form និង preventDefault
នៅពេល form ត្រូវបាន submit សកម្មភាពលំនាំដើមរបស់ browser គឺផ្ញើទិន្នន័យ ហើយ reload ទំព័រ។ ដើម្បីដោះស្រាយវាដោយខ្លួនឯង សូមស្តាប់ submit លើ form (មិនមែនប៊ូតុងទេ) ហើយហៅ preventDefault()៖
<form id="contact-form" novalidate>
<label>Email <input type="email" name="email" required></label>
<p id="form-message" role="status"></p>
<button type="submit">Send</button>
</form>
const form = document.querySelector("#contact-form");
const message = document.querySelector("#form-message");
form.addEventListener("submit", (event) => {
event.preventDefault();
const data = new FormData(form);
const email = String(data.get("email")).trim();
if (!email.includes("@")) {
message.textContent = "Please enter a valid email address.";
return;
}
message.textContent = "Thanks! Your message is ready to send.";
});
FormData អានគ្រប់ field តាម name របស់វា។ attribute novalidate បិទ popup របស់ browser ដើម្បីឲ្យសាររបស់អ្នកបង្ហាញជំនួស។ ការពិនិត្យសាមញ្ញនេះគ្រាន់តែជាការចាប់ផ្តើម៖ form validator ដែលអ្នកនឹងកែលម្អនៅពេលក្រោយ ត្រូវបានសាងសង់លើវា។
9. ប៊ូតុង Dark Mode ជាមួយ localStorage
feature ទីពីររក្សាទុកជម្រើសក្នុង browser។ localStorage រក្សាអត្ថបទតូចៗនៅលើកុំព្យូទ័ររបស់អ្នកទស្សនា ហើយអត្ថបទនោះនៅរស់ទោះបិទ tab ក៏ដោយ។ បន្ថែមប៊ូតុងទៅ header៖
<button type="button" id="theme-toggle" aria-pressed="false">Dark mode</button>
ក្នុង CSS កំណត់ពណ៌ជា variable ហើយបដិសេធវានៅពេល root element មាន data-theme="dark"៖
:root {
--bg: #fdf6e3;
--text: #333333;
}
:root[data-theme="dark"] {
--bg: #1b1b1f;
--text: #eeeeee;
}
body {
background-color: var(--bg);
color: var(--text);
}
ឥឡូវ JavaScript។ ជ្រើសរើស theme ដែលបានរក្សាទុកជាមុន បន្ទាប់មកជម្រើសរបស់ប្រព័ន្ធប្រតិបត្តិការ រួចទើប light៖
const themeButton = document.querySelector("#theme-toggle");
const root = document.documentElement;
function applyTheme(theme) {
root.dataset.theme = theme;
themeButton.setAttribute("aria-pressed", String(theme === "dark"));
localStorage.setItem("theme", theme);
}
const saved = localStorage.getItem("theme");
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
applyTheme(saved ?? (prefersDark ? "dark" : "light"));
themeButton.addEventListener("click", () => {
applyTheme(root.dataset.theme === "dark" ? "light" : "dark");
});
getItem ត្រឡប់ null នៅពេលគ្មានអ្វីត្រូវបានរក្សាទុក ហើយ ?? ប្រើតែផ្នែកខាងស្តាំនៅពេលតម្លៃជា null ឬ undefined ប៉ុណ្ណោះ។ Reload ទំព័រ៖ theme នៅដដែល។ ពិនិត្យ Application → Local Storage ក្នុង DevTools ដើម្បីមើល value ដែលបានរក្សាទុក។ កុំរក្សាទុកពាក្យសម្ងាត់ ឬទិន្នន័យឯកជននៅទីនោះ ព្រោះ script ណាក៏ដោយនៅលើទំព័រអាចអានវាបាន។
10. សាកល្បងដោយខ្លួនឯង
- រក និងផ្លាស់ប្តូរ។ ក្នុង console ដំណើរការ
document.querySelector("h1").textContent = "Test"។ បន្ទាប់មកសាកល្បង selector ដែលមិន match អ្វីទាំងអស់ ហើយអាន error។ - មើល XSS ដោយសុវត្ថិភាព។ នៅលើទំព័រហ្វឹកហាត់ កំណត់
innerHTMLរបស់ element ទៅ<b>bold</b>បន្ទាប់មកកំណត់textContentទៅ string ដូចគ្នា។ ប្រៀបធៀបអ្វីដែលអ្នកឃើញ ហើយពន្យល់ហេតុអ្វីtextContentមានសុវត្ថិភាពជាង។ - សាងសង់ filter។ បន្ថែមប៊ូតុង និង function
renderហើយធ្វើឲ្យ filter ដំណើរការដោយ listener តែមួយដែល delegate។ សម្គាល់ប៊ូតុងដែលកំពុងសកម្មដោយ toggle class ឈ្មោះactive។ - បង្ហាញចំនួន។ បន្ទាប់ពីការត្រងនីមួយៗ ធ្វើបច្ចុប្បន្នភាព
<p id="count">ជាមួយអត្ថបទដូចជា2 projects។ - បន្ថែម dark mode។ សាងសង់ប៊ូតុង toggle ជាមួយ
localStorage។ Reload បន្ទាប់មកសម្អាត value ដែលបានរក្សាទុកក្នុង DevTools ហើយ reload ម្តងទៀត។ តើមានអ្វីកើតឡើង? - ដោះស្រាយ form។ បន្ថែម submit handler។ ធ្វើឲ្យ field ទទេបង្ហាញសារ error ហើយបង្ហាញសារជោគជ័យតែនៅពេល email មាន
@ប៉ុណ្ណោះ។
បន្ទាប់ យើងនឹងផ្ទុកទិន្នន័យដែលមិនស្ថិតនៅក្នុងឯកសាររបស់អ្នកទាល់តែសោះ៖ asynchronous JavaScript និងការទាញយក project GitHub របស់ Dara តាមបណ្តាញ។
ទិញកាហ្វេជូនខ្ញុំ
ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!