ساخت سیستم جستجوی لحظهای (Instant Search) با Vanilla JS
✨نقشه راه جستجوی لحظهای شما: خلاصه و سریع!
رفیق برنامهنویس، این یک راهنمای جامع برای ساخت سیستم جستجوی لحظهای (Instant Search) با جاوااسکریپت خالص (Vanilla JS) هست. اینجا، قراره صفر تا صد قضیه رو با هم پیش بریم، از طراحی ساختار تا بهینهسازی نهایی. اگه آمادهای که تجربه کاربری سایتت رو متحول کنی و کاربران رو عاشق سرعت کنی، بزن بریم!
- 🚀 مقدمه و ایده کلی: چرا جستجوی لحظهای مهمه؟
- 🏗️ پایههای پروژه: HTML، CSS و ساختار داده.
- 🧠 قلب جستجو (Vanilla JS): منطق فیلتر و نمایش نتایج.
- ⚡ بهینهسازی و Debouncing: سرعت و کارایی برای تجربهای روان.
- 🎨 قشنگی و رسپانسیوی: چطور نتیجه رو خوب نشون بدیم.
- 🛠️ عیبیابی سریع: حل مشکلات رایج.
- ❓ سوالات متداول (FAQ): برای گوگل و شما.
همین الان شروع کن و پروژه رو تو گیتهاب بذار! اگه دنبال ابزارهای خفن دیگه هستی، حتماً یه سر به فروشگاه ابزارهای ما بزن!
مقدمه: چرا جستجوی لحظهای اینقدر تو دل برو هست؟
یادت میاد اون روزهایی که باید یه کلمه رو کامل تایپ میکردی، دکمه اینتر رو میزدی و بعد با استرس منتظر میموندی تا صفحه رفرش بشه و شاید نتایج ظاهر بشن؟ خب، اون روزها دیگه تموم شده! امروز، کاربران توقع دارن هرچیزی رو به صورت “آنلاین” و “لحظهای” دریافت کنن. جستجوی لحظهای (Instant Search) دقیقاً همین نیاز رو برآورده میکنه.
وقتی کاربر داره توی فیلد جستجو تایپ میکنه، سیستم همزمان شروع به فیلتر کردن و نمایش نتایج مرتبط میکنه. این کار نه تنها سرعت تعامل رو بالا میبره، بلکه تجربه کاربری رو به شدت ارتقا میده. کمتر کلیک، کمتر انتظار، بیشتر رضایت! به خصوص توی وبسایتهای فروشگاهی، بلاگها یا هرجایی که حجم محتوا بالاست، Instant Search مثل یک ناجی عمل میکنه.
حالا چرا Vanilla JS؟ چون سبک و قدرتمنده! نیازی به لود کردن کلی کتابخونه و فریمورک نداره و بهت کنترل کامل روی هر خط کد رو میده. این یعنی پرفورمنس عالی و انعطافپذیری بالا. پس آماده باش که با جاوااسکریپت خالص، جادو کنیم!
پایههای پروژه: ساختار HTML، ظاهر CSS و دادههای اولیه
قبل از اینکه بریم سراغ مغز پروژه، یعنی جاوااسکریپت، باید یه زیرساخت درست حسابی داشته باشیم. این بخش شامل سه قسمت اصلیه: ساختار HTML برای رابط کاربری، استایلدهی CSS برای زیبایی و رسپانسیوی، و البته آمادهسازی دادههایی که قراره جستجو بشن.
1. HTML: اسکلتبندی رابط کاربری
یه فیلد جستجو (input)، یه جایی برای نمایش نتایج (ul یا div) و شاید چندتا المنت دیگه. همین!
کد HTML پایه:
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>جستجوی لحظهای با Vanilla JS</title>
<!-- لینک به فایل CSS ما -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>جستجوگر محصول</h1>
<div class="search-box">
<input type="text" id="searchInput" placeholder="نام محصول را جستجو کنید..." aria-label="جستجوی محصول">
<div id="searchResults" class="results-container"></div>
</div>
<!-- این لیست در حالت عادی مخفیه و فقط برای دادههای اولیه است -->
<ul id="allProducts" style="display: none;">
<li data-name="لپ تاپ ایسوس مدل ZenBook" data-category="الکترونیک"></li>
<li data-name="گوشی سامسونگ گلکسی S23" data-category="الکترونیک"></li>
<li data-name="تلویزیون ال جی OLED" data-category="الکترونیک"></li>
<li data-name="کتاب هنر کدنویسی تمیز" data-category="کتاب"></li>
<li data-name="قهوه ساز دلونگی" data-category="لوازم خانگی"></li>
<li data-name="هدفون سونی WH-1000XM5" data-category="الکترونیک"></li>
<li data-name="کیبورد مکانیکال ریزر" data-category="لوازم جانبی"></li>
<li data-name="ماوس لاجیتک MX Master 3S" data-category="لوازم جانبی"></li>
<li data-name="دوربین کانن EOS R5" data-category="عکاسی"></li>
<li data-name="کفش ورزشی نایک" data-category="پوشاک"></li>
<li data-name="پاوربانک شیائومی 20000" data-category="لوازم جانبی"></li>
<li data-name="مانیتور خمیده سامسونگ" data-category="الکترونیک"></li>
<li data-name="مودم روتر TP-Link" data-category="شبکه"></li>
<li data-name="کوله پشتی کوهنوردی" data-category="ورزشی"></li>
<li data-name="هارد اکسترنال وسترن دیجیتال" data-category="ذخیره سازی"></li>
<li data-name="بازی God of War Ragnarök" data-category="بازی"></li>
</ul>
</div>
<!-- لینک به فایل جاوااسکریپت ما -->
<script src="script.js"></script>
</body>
</html>
2. CSS: زیبایی و واکنشگرایی
استایلها رو جوری مینویسیم که هم قشنگ باشه، هم تو هر صفحهای (موبایل، تبلت، لپتاپ، تلویزیون) به خوبی نمایش داده بشه. از Flexbox و Media Queries استفاده میکنیم.
کد CSS (فایل `style.css`):
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap');
body {
font-family: 'Vazirmatn', sans-serif;
direction: rtl; /* برای فارسی */
margin: 0;
padding: 20px;
background-color: #f4f7f6;
color: #333;
display: flex;
justify-content: center;
align-items: flex-start; /* تغییر به flex-start برای محتوای صفحه */
min-height: 100vh;
}
.container {
background-color: #ffffff;
padding: 30px;
border-radius: 12px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
max-width: 800px;
width: 100%;
margin-top: 50px; /* فاصله از بالای صفحه */
}
h1 {
color: #2C3E50;
text-align: center;
margin-bottom: 30px;
font-size: 2.5em;
}
.search-box {
position: relative;
margin-bottom: 20px;
}
#searchInput {
width: 100%;
padding: 15px 20px;
border: 2px solid #BDC3C7;
border-radius: 8px;
font-size: 1.2em;
outline: none;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
box-sizing: border-box; /* اطمینان از اینکه padding و border در width محاسبه میشوند */
}
#searchInput:focus {
border-color: #3498DB;
box-shadow: 0 0 10px rgba(52, 152, 219, 0.2);
}
.results-container {
background-color: #fcfcfc;
border: 1px solid #ECF0F1;
border-radius: 8px;
margin-top: 10px;
max-height: 300px; /* برای جلوگیری از پر شدن صفحه */
overflow-y: auto; /* اسکرول داخلی برای نتایج زیاد */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
z-index: 1000; /* اطمینان از اینکه روی بقیه محتوا قرار میگیرد */
position: absolute; /* برای اینکه دقیقا زیر input قرار بگیرد */
width: 100%;
display: none; /* در حالت عادی مخفی است */
}
.results-container.active {
display: block; /* زمانی که نتایج وجود دارند نمایش داده میشود */
}
.result-item {
padding: 12px 20px;
border-bottom: 1px solid #ECF0F1;
cursor: pointer;
transition: background-color 0.2s ease;
font-size: 1.1em;
color: #34495E;
display: flex;
justify-content: space-between;
align-items: center;
}
.result-item:last-child {
border-bottom: none;
}
.result-item:hover, .result-item.selected {
background-color: #EBF5FB;
color: #2980B9;
}
.result-category {
font-size: 0.85em;
color: #7F8C8D;
background-color: #ECF0F1;
padding: 4px 8px;
border-radius: 4px;
}
/* Media Queries برای واکنشگرایی */
@media (max-width: 768px) {
.container {
padding: 20px;
margin-top: 20px;
}
h1 {
font-size: 2em;
}
#searchInput {
font-size: 1em;
padding: 12px 15px;
}
.result-item {
font-size: 1em;
padding: 10px 15px;
}
}
@media (max-width: 480px) {
body {
padding: 10px;
}
.container {
border-radius: 8px;
box-shadow: none; /* در موبایل کوچک، سایه رو حذف میکنیم */
}
h1 {
font-size: 1.8em;
}
.search-box {
margin-bottom: 15px;
}
}
3. دادهها: چیزی که قراره جستجو بشه!
دادهها رو میشه از یک API گرفت، یا توی یک فایل JSON ذخیره کرد. برای سادگی اینجا، ما از <ul> مخفی در HTML استفاده کردیم و با JS اونها رو میخونیم. اما اگه حجم دادهها زیاده، بهتره از Fetch API برای گرفتن دادهها از سرور استفاده کنی.
قلب جستجو: منطق فیلتر و نمایش نتایج با Vanilla JS
اینجاست که جادو شروع میشه! قراره با جاوااسکریپت، ورودی کاربر رو بگیریم، دادهها رو فیلتر کنیم و نتایج رو به صورت پویا تو صفحه نمایش بدیم.
1. گرفتن ارجاعات (References)
اولین قدم، دسترسی به المنتهای HTML هست که باهاشون کار داریم. مثل فیلد جستجو و کانتینر نتایج.
کد JS (فایل `script.js` – بخش اول):
const searchInput = document.getElementById('searchInput');
const searchResults = document.getElementById('searchResults');
const allProductsElement = document.getElementById('allProducts');
// خواندن دادهها از لیست HTML (که مخفی است)
const products = Array.from(allProductsElement.children).map(li => ({
name: li.dataset.name,
category: li.dataset.category
}));
let selectedResultIndex = -1; // برای پیمایش با کیبورد
2. تابع جستجو و فیلتر (The Core Logic)
این تابع، هر بار که کاربر چیزی تایپ میکنه، فراخوانی میشه. ورودی کاربر رو میگیره، دادهها رو فیلتر میکنه و نتایج رو برای نمایش آماده میکنه. ما به دنبال تطابق بزرگ و کوچک (case-insensitive) هستیم و از متود includes() برای پیدا کردن زیررشتهها استفاده میکنیم.
کد JS (فایل `script.js` – تابع `displayResults`):
function displayResults(filteredProducts) {
searchResults.innerHTML = ''; // پاک کردن نتایج قبلی
selectedResultIndex = -1; // ریست کردن ایندکس انتخاب شده
if (filteredProducts.length === 0 && searchInput.value.trim() !== '') {
// اگر هیچ نتیجهای پیدا نشد
const noResultItem = document.createElement('div');
noResultItem.classList.add('result-item');
noResultItem.style.justifyContent = 'center';
noResultItem.style.color = '#E74C3C';
noResultItem.innerHTML = '<span style="margin-left: 5px; font-size: 1.2em;">💔</span> هیچ نتیجهای یافت نشد!';
searchResults.appendChild(noResultItem);
searchResults.classList.add('active');
return;
}
if (filteredProducts.length === 0 && searchInput.value.trim() === '') {
// اگر فیلد جستجو خالی است
searchResults.classList.remove('active');
return;
}
filteredProducts.forEach((product, index) => {
const item = document.createElement('div');
item.classList.add('result-item');
item.dataset.index = index; // برای پیمایش با کیبورد
// هایلایت کردن کلمه جستجو شده
const searchTerm = searchInput.value.toLowerCase();
const productNameLower = product.name.toLowerCase();
const highlightedName = product.name.replace(
new RegExp(searchTerm, 'gi'),
(match) => `<span style="font-weight: bold; color: #E67E22;">${match}</span>`
);
item.innerHTML = `
<span>${highlightedName}</span>
<span class="result-category">${product.category}</span>
`;
item.addEventListener('click', () => {
alert(`شما محصول: "${product.name}" از دستهبندی: "${product.category}" را انتخاب کردید.`);
searchInput.value = product.name;
searchResults.classList.remove('active'); // مخفی کردن نتایج
});
searchResults.appendChild(item);
});
searchResults.classList.add('active'); // نمایش کانتینر نتایج
}
function searchProducts(searchTerm) {
const lowerCaseSearchTerm = searchTerm.toLowerCase();
const filtered = products.filter(product =>
product.name.toLowerCase().includes(lowerCaseSearchTerm) ||
product.category.toLowerCase().includes(lowerCaseSearchTerm)
);
displayResults(filtered);
}
3. اضافه کردن Event Listener
حالا باید فیلد جستجو رو گوش به زنگ کنیم تا هر وقت کاربر چیزی تایپ کرد، تابع جستجوی ما فراخوانی بشه. از ایونت input استفاده میکنیم که بهترین گزینه برای این کاره.
کد JS (فایل `script.js` – Event Listener):
searchInput.addEventListener('input', (e) => {
const searchTerm = e.target.value.trim();
if (searchTerm.length > 0) {
searchProducts(searchTerm);
} else {
searchResults.innerHTML = '';
searchResults.classList.remove('active');
}
});
// وقتی کاربر روی جای دیگری به جز فیلد جستجو کلیک میکند، نتایج را مخفی کن
document.addEventListener('click', (e) => {
if (!searchResults.contains(e.target) && e.target !== searchInput) {
searchResults.classList.remove('active');
}
});
// مدیریت پیمایش با کیبورد (بالا و پایین)
searchInput.addEventListener('keydown', (e) => {
const resultItems = Array.from(searchResults.children);
if (resultItems.length === 0) return;
if (e.key === 'ArrowDown') {
e.preventDefault(); // جلوگیری از اسکرول صفحه
if (selectedResultIndex < resultItems.length - 1) {
selectedResultIndex++;
} else {
selectedResultIndex = 0; // رفتن به اول لیست
}
updateSelection(resultItems);
} else if (e.key === 'ArrowUp') {
e.preventDefault(); // جلوگیری از اسکرول صفحه
if (selectedResultIndex > 0) {
selectedResultIndex--;
} else {
selectedResultIndex = resultItems.length - 1; // رفتن به آخر لیست
}
updateSelection(resultItems);
} else if (e.key === 'Enter' && selectedResultIndex !== -1) {
e.preventDefault();
resultItems[selectedResultIndex].click(); // شبیهسازی کلیک روی آیتم
}
});
function updateSelection(items) {
items.forEach((item, index) => {
if (index === selectedResultIndex) {
item.classList.add('selected');
item.scrollIntoView({ block: 'nearest' }); // اسکرول به آیتم انتخاب شده
} else {
item.classList.remove('selected');
}
});
}
بهینهسازی و Debouncing: سرعت و کارایی برای تجربهای روان
تصور کن کاربر داره تندتند تایپ میکنه. اگه برای هر حرف، تابع جستجو رو فراخوانی کنیم، هم منابع سیستم رو مصرف کردیم، هم ممکنه UI کند بشه. اینجا Debouncing میاد وسط تا کارمون رو راحتتر کنه.
Debouncing چیست و چرا استفاده میشود؟
Debouncing یک تکنیک برنامهنویسی هست که جلوی فراخوانی بیش از حد یک تابع رو میگیره. به جای اینکه تابع searchProducts رو برای هر ضربه کلید (keypress) فراخوانی کنیم، یک تأخیر (مثلاً 300 میلیثانیه) ایجاد میکنیم. اگه کاربر در طول این تأخیر دوباره تایپ کنه، تایمر ریست میشه. تابع فقط زمانی اجرا میشه که کاربر برای مدت مشخصی دست از تایپ کردن بکشه. این کار باعث میشه تعداد فراخوانیهای تابع جستجو به حداقل برسه و عملکرد بهتری داشته باشیم.
اضافه کردن تابع Debounce به `script.js`:
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// حالا، Event Listener را به این شکل تغییر میدهیم:
const debouncedSearch = debounce(searchProducts, 300); // 300 میلیثانیه تاخیر
searchInput.addEventListener('input', (e) => {
const searchTerm = e.target.value.trim();
if (searchTerm.length > 0) {
debouncedSearch(searchTerm);
} else {
// اگر فیلد خالی شد، فوراً نتایج را پاک کن و debounce را کنسل کن
clearTimeout(debouncedSearch.timeoutId); // این خط ممکنه نیاز به دستکاری تابع debounce داشته باشد
searchResults.innerHTML = '';
searchResults.classList.remove('active');
}
});
// برای اینکه clearTimeout روی debouncedSearch.timeoutId کار کنه، تابع debounce رو کمی تغییر میدیم:
function debounceModified(func, delay) {
let timeoutId;
const debounced = function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
debounced.clear = () => clearTimeout(timeoutId); // اضافه کردن متود clear
return debounced;
}
const debouncedSearchWithClear = debounceModified(searchProducts, 300);
searchInput.addEventListener('input', (e) => {
const searchTerm = e.target.value.trim();
if (searchTerm.length > 0) {
debouncedSearchWithClear(searchTerm);
} else {
debouncedSearchWithClear.clear(); // پاک کردن تایمر اگر فیلد خالی شد
searchResults.innerHTML = '';
searchResults.classList.remove('active');
}
});
رسپانسیوی و تجربه کاربری (UX)
همونطور که تو بخش CSS دیدی، ما با استفاده از Media Queries مطمئن شدیم که ظاهر جستجوگرمون تو ابعاد مختلف صفحه، عالی به نظر میاد. اما UX فقط به ظاهر نیست، به احساس کاربر هم برمیگرده.
- پیمایش با کیبورد: ما قابلیت پیمایش بین نتایج با کلیدهای جهتنما (ArrowUp/ArrowDown) و انتخاب با Enter رو اضافه کردیم. این یه ویژگی فوقالعاده برای کاربرانی هست که دوست دارن با کیبورد کار کنن.
- هایلایت کردن نتایج: کلمهای که کاربر جستجو کرده رو تو نتایج هایلایت میکنیم تا پیدا کردنش راحتتر باشه.
- پیام “نتیجهای یافت نشد”: وقتی جستجو بینتیجه میمونه، به جای یه صفحه خالی، یه پیام دوستانه نشون میدیم. این جلوی سردرگمی کاربر رو میگیره.
- بستن نتایج: وقتی کاربر روی جای دیگه صفحه کلیک میکنه یا یه نتیجه رو انتخاب میکنه، نتایج جستجو رو مخفی میکنیم تا فضای صفحه شلوغ نشه.
- وضوح و خوانایی: فونت مناسب، اندازه متن خوب، و فاصله خطوط کافی برای افزایش خوانایی به کار بردیم. اینفراگرافیک متنی هم برای فهمیدن کل مقاله عالیه.
همه اینها در کنار هم، یک تجربه کاربری بینظیر رو رقم میزنن. فراموش نکن که هدف اصلی ما، حل مشکل کاربر و افزایش رضایت اونه. میتونستی با یه سر به تیم فنی ما بزنی و مشورت بگیری!
عیبیابی سریع (Troubleshooting)
بعضی وقتها، با اینکه همه چیز رو درست انجام دادی، باز هم مشکلاتی پیش میاد. اینجا چندتا از مشکلات رایج و راهحلهاشون رو باهم مرور میکنیم.
مشکل: جستجو کار نمیکند یا نتایج نشان داده نمیشوند.
راهحلها:
- شناسه المنتها: مطمئن شو که
id="searchInput"وid="searchResults"وid="allProducts"رو دقیقاً تو HTMLت گذاشتی. - لینک فایلهای JS و CSS: مطمئن شو که فایلهای
style.cssوscript.jsرو به درستی تو HTML لینک کردی و مسیرهاشون صحیحه. فایل JS رو قبل از تگ پایانی</body>قرار بده. - Console Log: مرورگرت رو باز کن (F12)، تب Console رو ببین. آیا خطایی هست؟ معمولاً خطاهای جاوااسکریپت اونجا خودشون رو نشون میدن.
- دادههای
products: مطمئن شو که آرایهproductsدرست پر شده و دارای آبجکتهایی با پراپرتیnameوcategoryهست.
مشکل: Debouncing به درستی کار نمیکند یا تأخیر زیادی دارد.
راهحلها:
- مقدار
delay: مقدار تأخیر (300 میلیثانیه در مثال ما) را تغییر بده. ممکن است برای پروژه تو، نیاز به مقدار کمتر یا بیشتر باشد. - نحوه فراخوانی: مطمئن شو که تابع
searchProductsرو مستقیماً بهaddEventListenerندادی، بلکه نسخهdebouncedرو استفاده کردی. - عدم لغو تایمر: اگه بعد از پاک کردن فیلد جستجو، نتایج دیر پاک میشن، مطمئن شو که
debouncedSearchWithClear.clear()رو تو بخشelseمربوط بهinputایونت گذاشتی.
مشکل: پیمایش با کیبورد یا هایلایت نتایج کار نمیکند.
راهحلها:
- Class های
selected: چک کن که تو CSS برای کلاس.result-item.selectedاستایل دادی تا موقع انتخاب، آیتم قابل تشخیص باشه. - `data-index`: مطمئن شو که هر
.result-itemتو تابعdisplayResultsدارایdata-indexهست. - `e.preventDefault()`: این خط کد برای جلوگیری از عملکرد پیشفرض مرورگر (مثل اسکرول کردن) حیاتیه. مطمئن شو که برای
ArrowUpوArrowDownدرست استفاده شده.
اگه بازم مشکلی داری، میتونی به این شماره زنگ بزنی یا به بخش تماس با تیم فنی ما سر بزنی. همواره آماده یاری هستیم!
پرسشهای متداول (FAQ)
آیا سیستم جستجوی لحظهای بر روی موبایل هم به خوبی کار میکند؟
بله، با استفاده از طراحی واکنشگرا (Responsive Design) در CSS و استفاده از واحدهای نسبی مثل em و %، این سیستم روی تمامی دستگاهها از جمله موبایل و تبلت بهینه و زیبا نمایش داده میشود. ما از Media Queries برای تطابق با اندازههای مختلف صفحه استفاده کردیم.
آیا میتوانم این سیستم جستجو را برای دادههای بسیار بزرگ (مثلاً 100 هزار رکورد) استفاده کنم؟
برای دادههای بسیار بزرگ، توصیه میشود منطق جستجو را به جای سمت کلاینت (جاوااسکریپت مرورگر) به سمت سرور منتقل کنید. در این حالت، Vanilla JS وظیفه ارسال درخواست جستجو به یک API سرور و نمایش نتایج برگشتی را بر عهده خواهد داشت. این رویکرد بار پردازشی را از روی مرورگر کاربر برداشته و سرعت را به شدت افزایش میدهد. برای این مورد میتونی از ابزارهای اختصاصی ما کمک بگیری.
چطور میتوانم سرعت جستجو را بهبود دهم؟
استفاده از تکنیک Debouncing (که در مقاله توضیح داده شد) اولین و مهمترین قدم است. همچنین، اطمینان از بهینهسازی ساختار دادهها (مثلاً استفاده از آرایهای از آبجکتها به جای پیمایش DOM) و استفاده از الگوریتمهای جستجوی کارآمد میتواند به بهبود سرعت کمک کند. برای حجم بالای داده، جستجوی سمت سرور ضروری است.
آیا امکان اضافه کردن فیلترهای پیشرفتهتر (مثل فیلتر بر اساس دسته بندی یا قیمت) وجود دارد؟
قطعاً! با گسترش منطق تابع searchProducts و افزودن ورودیهای اضافی به HTML (مثلاً فیلدهای select برای دسته بندی یا range input برای قیمت)، میتوانید فیلترهای پیشرفتهتری را پیادهسازی کنید. هر فیلتر میتواند یک شرط اضافی به متود filter() جاوااسکریپت اضافه کند.
چگونه میتوانم کدهای آماده و اسنیپتهای جاوااسکریپت بیشتری پیدا کنم؟
برای دسترسی به مجموعهای از کدهای آماده و اسنیپتهای جاوااسکریپت و سایر زبانها، به صفحه کدهای آماده و اسنیپتها در سایت ما مراجعه کنید. این بخش به صورت مداوم با محتوای جدید و کاربردی بهروزرسانی میشود.


