DOM در جاوااسکریپت
بهنام نوبخت · ۱۴۰۵/۷/۱۱
تا اینجا با مفاهیم پایه جاوااسکریپت مانند متغیرها، شرطها، حلقهها، توابع، آرایهها، Objectها، Stringها، Numberها و Date آشنا شدیم. اما بیشتر مثالهای قبلی در محیط جاوااسکریپت مستقل از صفحه HTML اجرا میشدند.
در توسعه وب معمولاً هدف ما فقط اجرای کد جاوااسکریپت نیست؛ بلکه میخواهیم با استفاده از جاوااسکریپت محتوای صفحه را تغییر دهیم، عناصر جدید ایجاد کنیم، اطلاعات کاربران را نمایش دهیم، کلاسهای CSS را تغییر دهیم و به تعاملات کاربر پاسخ دهیم.
برای انجام این کار در مرورگر از مفهومی به نام DOM استفاده میکنیم.
DOM یکی از مهمترین مفاهیم جاوااسکریپت در طراحی و توسعه صفحات وب است و در ادامه مسیر یادگیری جاوااسکریپت، پایه بسیاری از مباحث مانند Eventها، فرمها، اعتبارسنجی و Web APIها خواهد بود.
DOM چیست؟
DOM مخفف:
Document Object Model
است.
به زبان ساده، مرورگر زمانی که یک صفحه HTML را بارگذاری میکند، ساختار HTML آن صفحه را به شکل یک ساختار درختی از Objectها در حافظه ایجاد میکند.
جاوااسکریپت میتواند از طریق این ساختار:
عناصر HTML را پیدا کند.
محتوای عناصر را تغییر دهد.
ویژگیهای HTML را تغییر دهد.
CSS را تغییر دهد.
عناصر جدید ایجاد کند.
عناصر را حذف کند.
کلاسهای CSS را اضافه یا حذف کند.
ساختار صفحه را به صورت پویا تغییر دهد.
برای مثال HTML زیر را در نظر بگیرید:
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Hello جاوااسکریپت</h1>
<p>This is a paragraph.</p>
<button>Click Me</button>
</body>
</html>مرورگر این ساختار را به شکلی شبیه به یک درخت در نظر میگیرد:
Document
│
└── html
│
├── head
│ └── title
│
└── body
│
├── h1
├── p
└── buttonاین ساختار همان چیزی است که جاوااسکریپت میتواند از طریق DOM با آن کار کند.
Document چیست؟
در جاوااسکریپت مرورگر، شیء بسیار مهمی به نام:
documentوجود دارد.
document نماینده صفحه HTML فعلی است.
مثلاً:
console.log(document);میتوانیم اطلاعات مربوط به سند HTML فعلی را از طریق آن دریافت کنیم.
در واقع بسیاری از عملیات DOM از همین شیء document شروع میشوند.
اولین مثال DOM
فرض کنید فایل HTML ما به شکل زیر است:
<!DOCTYPE html>
<html>
<head>
<title>DOM Example</title>
</head>
<body>
<h1>Hello World</h1>
<script>
console.log(document);
</script>
</body>
</html>در این مثال جاوااسکریپت به صفحه HTML دسترسی دارد و میتواند ساختار آن را از طریق document مشاهده کند.
پیدا کردن عناصر HTML
اولین کاری که معمولاً با DOM انجام میدهیم، پیدا کردن یک عنصر HTML است.
جاوااسکریپت روشهای مختلفی برای این کار دارد.
مهمترین روشها عبارتاند از:
document.getElementById()document.getElementsByClassName()document.getElementsByTagName()document.querySelector()document.querySelectorAll()در ادامه هرکدام را بررسی میکنیم.
متد getElementById
اگر یک عنصر HTML دارای id باشد، میتوانیم آن را با getElementById() پیدا کنیم.
HTML:
<h1 id="title">Hello World</h1>جاوااسکریپت:
const title = document.getElementById("title");
console.log(title);در اینجا جاوااسکریپت عنصری را پیدا میکند که:
id = "title"دارد.
تغییر محتوای یک عنصر
یکی از سادهترین کارهایی که با DOM انجام میدهیم، تغییر محتوای یک عنصر است.
مثلاً:
<h1 id="title">Hello World</h1>و:
const title = document.getElementById("title");
title.textContent = "Hello جاوااسکریپت";اکنون متن صفحه از:
Hello Worldبه:
Hello جاوااسکریپتتغییر میکند.
textContent چیست؟
ویژگی:
textContentبرای خواندن یا تغییر متن یک عنصر استفاده میشود.
برای خواندن متن:
<p id="message">Welcome to جاوااسکریپت</p>const message = document.getElementById("message");
console.log(message.textContent);خروجی:
Welcome to جاوااسکریپتبرای تغییر:
message.textContent = "Welcome!";تغییر محتوای HTML با innerHTML
ویژگی دیگری به نام:
innerHTMLوجود دارد.
با استفاده از آن میتوان محتوای HTML داخل یک عنصر را خواند یا تغییر داد.
مثلاً:
<div id="box"></div>جاوااسکریپت:
const box = document.getElementById("box");
box.innerHTML = "<strong>Hello جاوااسکریپت</strong>";اکنون داخل div یک عنصر strong ایجاد شده است.
اگر از:
box.textContent = "<strong>Hello</strong>";استفاده کنیم، تگ HTML اجرا نمیشود و به صورت متن نمایش داده میشود.
بنابراین تفاوت ساده آنها:
textContent → Text
innerHTML → HTMLیک نکته امنیتی درباره innerHTML
innerHTML ابزار قدرتمندی است، اما نباید هر محتوایی را که مستقیماً از کاربر یا منبع غیرقابل اعتماد دریافت کردهایم بدون بررسی داخل آن قرار دهیم.
برای مثال قرار دادن مستقیم ورودی کاربر در innerHTML میتواند در شرایط خاص باعث مشکلات امنیتی مانند XSS شود.
برای نمایش متن ساده که از کاربر دریافت میشود، معمولاً textContent انتخاب امنتری است.
متد getElementsByClassName
اگر چند عنصر دارای یک کلاس CSS باشند، میتوانیم آنها را با:
document.getElementsByClassName()پیدا کنیم.
HTML:
<p class="message">Message 1</p>
<p class="message">Message 2</p>
<p class="message">Message 3</p>جاوااسکریپت:
const messages =
document.getElementsByClassName("message");
console.log(messages);در این حالت چند عنصر دریافت میکنیم.
دسترسی به عناصر مجموعه
چون ممکن است چند عنصر پیدا شده باشند، میتوانیم با index به آنها دسترسی پیدا کنیم:
console.log(messages[0]);
console.log(messages[1]);
console.log(messages[2]);همانند آرایه، index از 0 شروع میشود.
مثلاً:
messages[0].textContent = "First Message";تغییر چند عنصر
میتوانیم با یک حلقه همه عناصر را تغییر دهیم:
const messages =
document.getElementsByClassName("message");
for (let i = 0; i < messages.length; i++) {
messages[i].textContent = "Updated";
}اکنون متن تمام عناصر تغییر میکند.
متد getElementsByTagName
میتوانیم عناصر را بر اساس نام Tag نیز پیدا کنیم.
مثلاً:
const paragraphs =
document.getElementsByTagName("p");
console.log(paragraphs);تمام عناصر p صفحه پیدا میشوند.
مثلاً:
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.color = "blue";
}در این مثال رنگ متن تمام pها تغییر میکند.
متد querySelector
یکی از مهمترین روشهای انتخاب عناصر در DOM:
document.querySelector()است.
این متد اولین عنصری را که با یک CSS Selector مطابقت داشته باشد برمیگرداند.
مثلاً:
<h1 id="title">Hello</h1>میتوانیم بنویسیم:
const title = document.querySelector("#title");علامت # برای انتخاب id استفاده میشود.
انتخاب با Class
HTML:
<p class="message">Hello</p>جاوااسکریپت:
const message =
document.querySelector(".message");علامت . برای انتخاب کلاس استفاده میشود.
انتخاب با Tag
مثلاً:
const paragraph =
document.querySelector("p");اولین عنصر p را پیدا میکند.
querySelector و CSS Selectorها
یکی از مزایای querySelector() این است که میتوانیم از Selectorهای آشنای CSS استفاده کنیم.
مثلاً:
document.querySelector("#title");برای id
document.querySelector(".box");برای class
و:
document.querySelector("button");برای Tag
همچنین:
document.querySelector(".container p");برای پیدا کردن اولین p داخل عنصری با کلاس container.
متد querySelectorAll
اگر بخواهیم تمام عناصر مطابق یک Selector را پیدا کنیم، از:
document.querySelectorAll()استفاده میکنیم.
HTML:
<p class="message">One</p>
<p class="message">Two</p>
<p class="message">Three</p>جاوااسکریپت:
const messages =
document.querySelectorAll(".message");
console.log(messages);تمام عناصر دارای کلاس message انتخاب میشوند.
پیمایش عناصر با querySelectorAll
میتوانیم با حلقه for روی آنها حرکت کنیم:
const messages =
document.querySelectorAll(".message");
for (let i = 0; i < messages.length; i++) {
messages[i].textContent = "Updated";
}همچنین میتوانیم از for...of استفاده کنیم:
const messages =
document.querySelectorAll(".message");
for (const message of messages) {
message.textContent = "Updated";
}تفاوت querySelector و querySelectorAll
تفاوت اصلی:
querySelector()فقط اولین عنصر مطابق Selector را برمیگرداند.
در حالی که:
querySelectorAll()تمام عناصر مطابق Selector را برمیگرداند.
مثلاً:
const first =
document.querySelector(".item");در مقابل:
const items =
document.querySelectorAll(".item");تغییر CSS با جاوااسکریپت
جاوااسکریپت میتواند Style یک عنصر را نیز تغییر دهد.
HTML:
<h1 id="title">Hello</h1>جاوااسکریپت:
const title =
document.getElementById("title");
title.style.color = "red";رنگ متن قرمز میشود.
تغییر چند ویژگی CSS
title.style.color = "red";
title.style.backgroundColor = "yellow";
title.style.fontSize = "40px";توجه کنید که در جاوااسکریپت بعضی نامهای CSS که در CSS دارای - هستند، به شکل متفاوتی نوشته میشوند.
CSS:
background-colorجاوااسکریپت:
backgroundColorCSS:
font-sizeجاوااسکریپت:
fontSizeخواندن مقدار Attributeها
برای کار با ویژگیهای HTML میتوانیم از:
getAttribute()استفاده کنیم.
مثلاً:
<a id="link" href="https://example.com">
Website
</a>جاوااسکریپت:
const link =
document.getElementById("link");
console.log(
link.getAttribute("href")
);خروجی مقدار href خواهد بود.
تغییر Attribute
برای تغییر Attribute میتوانیم از:
setAttribute()استفاده کنیم.
مثلاً:
link.setAttribute(
"href",
"https://example.org"
);اکنون مقدار href تغییر کرده است.
حذف Attribute
برای حذف یک Attribute:
link.removeAttribute("href");استفاده میکنیم.
بررسی وجود Attribute
میتوانیم بررسی کنیم که یک Attribute وجود دارد یا خیر:
if (link.hasAttribute("href")) {
console.log("Href exists");
}کار با id
میتوانیم id یک عنصر را مستقیماً تغییر دهیم:
const title =
document.getElementById("title");
title.id = "main-title";کار با class
یکی از بخشهای مهم DOM، کار با کلاسهای CSS است.
جاوااسکریپت برای این کار ویژگی:
classListرا در اختیار ما قرار میدهد.
مثلاً:
<div id="box" class="box"></div>میتوانیم کلاس جدید اضافه کنیم:
const box =
document.getElementById("box");
box.classList.add("active");اکنون:
<div id="box" class="box active"></div>داریم.
حذف کلاس
box.classList.remove("active");بررسی کلاس
if (box.classList.contains("active")) {
console.log("Active");
}تغییر وضعیت کلاس با toggle
یکی از پرکاربردترین متدهای classList:
toggle()است.
box.classList.toggle("active");اگر کلاس وجود نداشته باشد، اضافه میشود.
اگر وجود داشته باشد، حذف میشود.
این قابلیت در ساخت منوها، Dark Mode، Modalها و عناصر تعاملی بسیار کاربرد دارد.
ایجاد یک عنصر جدید
تا اینجا عناصر موجود در HTML را انتخاب کردیم.
اما جاوااسکریپت میتواند عنصر جدید نیز ایجاد کند.
برای این کار از:
document.createElement()استفاده میکنیم.
مثلاً:
const paragraph =
document.createElement("p");
console.log(paragraph);یک عنصر p ساخته شده است، اما هنوز آن را به صفحه اضافه نکردهایم.
قرار دادن متن در عنصر جدید
const paragraph =
document.createElement("p");
paragraph.textContent =
"This paragraph was created with جاوااسکریپت.";اکنون عنصر ساخته شده و دارای متن است.
اضافه کردن عنصر به صفحه
برای قرار دادن عنصر در صفحه میتوانیم از:
appendChild()استفاده کنیم.
مثلاً:
<div id="container"></div>جاوااسکریپت:
const container =
document.getElementById("container");
const paragraph =
document.createElement("p");
paragraph.textContent =
"Hello from جاوااسکریپت";
container.appendChild(paragraph);اکنون p داخل div قرار گرفته است.
ایجاد چند عنصر به صورت پویا
میتوانیم با یک حلقه چند عنصر ایجاد کنیم:
const container =
document.getElementById("container");
for (let i = 1; i <= 5; i++) {
const item =
document.createElement("p");
item.textContent =
`Item ${i}`;
container.appendChild(item);
}خروجی صفحه شامل پنج پاراگراف خواهد بود.
حذف یک عنصر
برای حذف یک عنصر میتوانیم از:
remove()استفاده کنیم.
مثلاً:
const paragraph =
document.querySelector("p");
paragraph.remove();اولین p صفحه حذف میشود.
حذف فرزند از والد
روش دیگر استفاده از removeChild() است:
const container =
document.getElementById("container");
const paragraph =
container.querySelector("p");
container.removeChild(paragraph);در این روش عنصر از طریق والد خود حذف میشود.
رابطه Parent و Child
در DOM عناصر HTML رابطه والد و فرزند دارند.
مثلاً:
<div id="parent">
<p>First</p>
<p>Second</p>
</div>در اینجا:
div
├── p
└── pعنصر div والد و عناصر p فرزند آن هستند.
parentElement
میتوانیم والد یک عنصر را پیدا کنیم:
const paragraph =
document.querySelector("p");
console.log(
paragraph.parentElement
);children
برای دریافت فرزندان یک عنصر:
const container =
document.getElementById("parent");
console.log(container.children);میتوانیم با index به فرزندان دسترسی داشته باشیم:
console.log(container.children[0]);
console.log(container.children[1]);firstElementChild
برای دریافت اولین فرزند:
console.log(
container.firstElementChild
);lastElementChild
برای دریافت آخرین فرزند:
console.log(
container.lastElementChild
);nextElementSibling
میتوانیم عنصر بعدی یک عنصر را نیز پیدا کنیم:
const first =
container.firstElementChild;
console.log(
first.nextElementSibling
);previousElementSibling
برای دریافت عنصر قبلی:
const second =
container.lastElementChild;
console.log(
second.previousElementSibling
);این قابلیتها در پیمایش DOM بسیار کاربردی هستند.
مثال عملی: تغییر عنوان صفحه
HTML:
<h1 id="title">
عنوان قدیمی
</h1>جاوااسکریپت:
const title =
document.getElementById("title");
title.textContent =
"عنوان جدید";مثال عملی: تغییر وضعیت یک محصول
فرض کنید یک محصول داریم:
<div id="product">
<h2 id="product-name">
Laptop
</h2>
<p id="product-status">
Available
</p>
</div>میتوانیم وضعیت را تغییر دهیم:
const status =
document.getElementById("product-status");
status.textContent =
"Out of Stock";مثال عملی: ساخت لیست با جاوااسکریپت
HTML:
<ul id="users"></ul>جاوااسکریپت:
const users = [
"Ali",
"Sara",
"Reza",
"Mina"
];
const userList =
document.getElementById("users");
for (const user of users) {
const li =
document.createElement("li");
li.textContent = user;
userList.appendChild(li);
}جاوااسکریپت در اینجا اطلاعات موجود در آرایه را گرفته و برای هر کاربر یک li ساخته است.
این الگو در پروژههای واقعی بسیار مهم است.
مثال عملی: نمایش تعداد کاربران
HTML:
<h2>
Users:
<span id="user-count"></span>
</h2>جاوااسکریپت:
const users = [
"Ali",
"Sara",
"Reza",
"Mina"
];
const count =
document.getElementById("user-count");
count.textContent = users.length;صفحه به صورت پویا تعداد کاربران را نمایش میدهد.
مثال عملی: تغییر کلاس بر اساس وضعیت
HTML:
<div id="status">
Active
</div>جاوااسکریپت:
const status =
document.getElementById("status");
status.classList.add("active");بعداً میتوانیم با CSS برای کلاس active ظاهر خاصی تعریف کنیم.
DOM و جاوااسکریپت چه رابطهای دارند؟
نکته مهم این است که DOM خود جاوااسکریپت نیست.
DOM یک مدل از سند HTML است که مرورگر در اختیار جاوااسکریپت قرار میدهد.
جاوااسکریپت از APIهای مرورگر استفاده میکند تا بتواند با DOM کار کند.
به صورت ساده:
HTML
↓
Browser
↓
DOM
↓
جاوااسکریپت
↓
Change Pageبنابراین وقتی میگوییم:
document.getElementById("title")جاوااسکریپت از APIهای DOM مرورگر استفاده میکند تا یک عنصر HTML را پیدا کند.
تفاوت DOM و HTML
HTML همان کدی است که ساختار صفحه را تعریف میکند.
مثلاً:
<h1>Hello</h1>اما DOM نمایش ساختاری همین سند در حافظه مرورگر است.
جاوااسکریپت میتواند DOM را تغییر دهد و در نتیجه چیزی که کاربر در صفحه مشاهده میکند نیز تغییر کند.
مثلاً HTML اولیه:
<h1 id="title">Hello</h1>بعد از اجرای:
document.getElementById("title").textContent =
"Hello جاوااسکریپت";کاربر متن جدید را میبیند.
یک نکته مهم درباره زمان اجرای جاوااسکریپت
اگر جاوااسکریپت قبل از ساخته شدن عنصر HTML اجرا شود، ممکن است نتواند آن عنصر را پیدا کند.
مثلاً:
<script>
const title =
document.getElementById("title");
console.log(title);
</script>
<h1 id="title">
Hello
</h1>در این شرایط ممکن است مقدار title برابر null باشد، چون مرورگر هنوز به h1 نرسیده است.
یکی از روشهای ساده برای جلوگیری از این مشکل قرار دادن Script در انتهای body است:
<body>
<h1 id="title">
Hello
</h1>
<script src="app.js"></script>
</body>در مقالات آینده با روشهای استانداردتر مدیریت زمان اجرای جاوااسکریپت و Eventها بیشتر آشنا خواهیم شد.
اگر عنصر پیدا نشود چه میشود؟
مثلاً:
const title =
document.getElementById("unknown");
console.log(title);اگر چنین عنصری وجود نداشته باشد، نتیجه:
nullخواهد بود.
بنابراین باید در موارد لازم بررسی کنیم:
if (title !== null) {
title.textContent = "Hello";
}اشتباهات رایج در DOM
اشتباه اول: اشتباه در id
HTML:
<h1 id="title">Hello</h1>اما جاوااسکریپت:
document.getElementById("Title");title و Title یکسان نیستند.
جاوااسکریپت به حروف بزرگ و کوچک حساس است.
اشتباه دوم: فراموش کردن
در querySelector() برای id باید از # استفاده کنیم:
document.querySelector("#title");و برای class:
document.querySelector(".message");اشتباه سوم: استفاده از querySelector برای انتخاب همه عناصر
این کد فقط اولین عنصر را انتخاب میکند:
document.querySelector(".item");برای انتخاب همه موارد:
document.querySelectorAll(".item");اشتباه چهارم: اشتباه گرفتن textContent و innerHTML
اگر قصد نمایش متن ساده داریم:
element.textContent = value;اما اگر عمداً میخواهیم HTML ایجاد کنیم:
element.innerHTML = value;
استفاده میشود.
اشتباه پنجم: اجرای زودهنگام جاوااسکریپت
اگر Script قبل از ایجاد عناصر HTML اجرا شود، ممکن است عنصر موردنظر پیدا نشود.
اشتباه ششم: تغییر مستقیم innerHTML با ورودی کاربر
این کار:
element.innerHTML = userInput;
در برنامههای واقعی میتواند از نظر امنیتی خطرناک باشد.
برای متن ساده بهتر است:
element.textContent = userInput;استفاده شود.
جدول متدهای مهم DOM
متد یا ویژگیکاربرد | |
|---|---|
| انتخاب عنصر با ID |
| انتخاب عناصر با Class |
| انتخاب عناصر با Tag |
| انتخاب اولین عنصر مطابق CSS Selector |
| انتخاب تمام عناصر مطابق CSS Selector |
| خواندن یا تغییر متن |
| خواندن یا تغییر HTML داخلی |
| تغییر مستقیم Style |
| دریافت Attribute |
| تغییر یا ایجاد Attribute |
| حذف Attribute |
| بررسی وجود Attribute |
| اضافه کردن Class |
| حذف Class |
| بررسی Class |
| اضافه یا حذف متناوب Class |
| ایجاد عنصر جدید |
| اضافه کردن فرزند |
| حذف عنصر |
| دریافت والد |
| دریافت فرزندان |
| اولین فرزند |
| آخرین فرزند |
تمرینهای مقاله
تمرین ۱
یک صفحه HTML ایجاد کنید که شامل:
h1
p
buttonباشد.
سپس با جاوااسکریپت متن h1 و p را تغییر دهید.
تمرین ۲
سه عنصر با کلاس:
itemایجاد کنید.
با querySelectorAll() همه آنها را انتخاب کرده و متنشان را تغییر دهید.
تمرین ۳
یک div با id زیر ایجاد کنید:
containerسپس با جاوااسکریپت پنج عنصر p ایجاد کرده و داخل آن قرار دهید.
تمرین ۴
یک لینک ایجاد کنید و با جاوااسکریپت مقدار href آن را تغییر دهید.
تمرین ۵
یک عنصر با کلاس:
boxایجاد کنید.
با جاوااسکریپت کلاس:
activeرا اضافه و سپس حذف کنید.
تمرین ۶
یک آرایه از نام کاربران ایجاد کنید:
const users = [
"Ali",
"Sara",
"Reza",
"Mina",
"Hassan"
];سپس با جاوااسکریپت یک لیست HTML بسازید و نام تمام کاربران را داخل آن قرار دهید.
چالش عملی
یک Product List ساده با جاوااسکریپت ایجاد کنید.
آرایهای مانند زیر داشته باشید:
const products = [
{
name: "Laptop",
price: 500
},
{
name: "Phone",
price: 300
},
{
name: "Headphone",
price: 80
}
];در HTML یک container ایجاد کنید:
<div id="products"></div>
سپس با جاوااسکریپت:
آرایه را پیمایش کنید.
برای هر محصول یک
divایجاد کنید.نام محصول را نمایش دهید.
قیمت را نمایش دهید.
عناصر ایجادشده را به
productsاضافه کنید.
هدف این تمرین این است که بتوانید از ترکیب:
Array
Object
Loop
DOM
createElement
textContent
appendChildاستفاده کنید.
جمعبندی
در این مقاله با یکی از مهمترین مفاهیم جاوااسکریپت در توسعه وب یعنی DOM آشنا شدیم.
یاد گرفتیم که مرورگر ساختار HTML را به صورت یک مدل درختی از Objectها در اختیار جاوااسکریپت قرار میدهد و ما میتوانیم با استفاده از آن صفحه را به صورت پویا تغییر دهیم.
مهمترین مواردی که یاد گرفتیم:
DOM چیست.
documentچیست.انتخاب عنصر با
getElementById()انتخاب عناصر با
getElementsByClassName()انتخاب عناصر با
getElementsByTagName()استفاده از
querySelector()استفاده از
querySelectorAll()تغییر متن با
textContentتغییر HTML با
innerHTMLتغییر CSS با
styleکار با Attributeها
کار با
classListایجاد عنصر با
createElement()اضافه کردن عنصر با
appendChild()حذف عناصر
پیمایش والد و فرزندان
تفاوت HTML و DOM
اهمیت زمان اجرای جاوااسکریپت
نکات امنیتی مربوط به
innerHTML
تا اینجا میتوانیم با جاوااسکریپت محتوای صفحه را تغییر دهیم، اما هنوز یک بخش بسیار مهم باقی مانده است: چگونه وقتی کاربر روی یک دکمه کلیک میکند یا چیزی را وارد میکند، جاوااسکریپت اجرا شود؟
نظرات
هنوز نظری ثبت نشده است.