شنبه ۲۲ شهریور ۱۴۰۴

Saturday, September 13, 2025 GMT +3:30

ساخت منوی آکاردئونی با جاوا اسکریپت و CSS

javascript-accordion-box

ساخت منوها و باکس های آکاردئونی (accordion) یا به اصطلاح جمع شونده، یکی از قابلیت هایی است که جاوا اسکریپت (JavaScript) و کتابخانه های زیرمجموعه آن مانند جی کئوری (jQuery) در اختیار برنامه نویسان و طراحان وب قرار می دهند، قابلیت تعاملی و زیبایی که این نوع منوها به رابط کاربری (Interface) سایت یا وبلاگ می دهد باعث می شود که خیلی از مدیران وب گرایش به سمت استفاده از آن داشته باشند، البته در این مورد باید همیشه به مقوله سازگاری، سرعت و سبکی صفحات دقت نمود، چرا که هرچند می توانیم جلوه های خیلی خاصی در صفحات وب ایجاد کنیم، اما باید توجه داشت که این جلوه ها سرعت بارگذاری و قابلیت سازگاری سایت یا وبلاگمان را در مرورگرها و سیستم های مختلف تحت تاثیر قرار ندهند، از این رو است که همیشه استفاده از کدهای کم حجم با بیشترین سازگاری توصیه می شود.

منظور از منوی آکاردئون چیست؟


منوی آکاردئونی در واقع برگرفته از نام واژه آکاردئون (accordion) و به معنی یک نوع ساز بادی معروف است، قسمتی از این ساز دارای یک مجاری عبور هوای فنر مانند و پله پله ای است که نوازنده برای نواختن آهنگ باید آن را با دست خود به طور متناوب حرکت دهد، این ساز قدمت زیادی داشته و در خیلی از فیلم ها و سریال ها معمولا به عنوان ساز بینوایان استفاده می شود! به خاطر شباهت این نوع منو با این ساز به آن آکاردئونی می گوییم.

کد جاوا اسکریپت برای ساخت باکس آکاردئونی


همان طور که گفتیم برای ساختن منوها و باکس های آکاردئونی یا به اصلاح جمع شونده، می توان از جاوا اسکریپت استفاده کرد، از این رو در زیر یکی از سبک ترین و در عین حال سازگارترین توابعی که بدین منظور نوشته شده را با هم بررسی می کنیم.
<script type="text/javascript">
//<![CDATA[
var contentHeight = 34;
var TimeToSlide = 300.0;
var openprobox = '';
function runprobox(index){
    var divID = "probox" + index + "content";
    if(openprobox == divID){
        divID = '';
    }
    setTimeout("animate(" + new Date().getTime() + "," + TimeToSlide + ",'" + openprobox + "','" + divID + "')", 33);
    openprobox = divID;
}
function animate(lastTick, timeLeft, closingId, openingId){
    var curTick = new Date().getTime();
    var elapsedTicks = curTick - lastTick;
    var opening = (openingId == '') ? null : document.getElementById(openingId);
    var closing = (closingId == '') ? null : document.getElementById(closingId);
    
    if(timeLeft <= elapsedTicks){
        if(opening != null){
            opening.style.height = contentHeight + 'px';
        }
        if(closing != null){
            closing.style.display = 'none';
            closing.style.height = '0px';
        }
    return;
    }
    timeLeft -= elapsedTicks;
  var newClosedHeight = Math.round((timeLeft/TimeToSlide) * contentHeight);
  if(opening != null){
      if(opening.style.display != 'block'){
          opening.style.display = 'block';
      }
      opening.style.height = (contentHeight - newClosedHeight) + 'px';
  }
  if(closing != null){
      closing.style.height = newClosedHeight + 'px';
  }
  setTimeout("animate(" + curTick + "," + timeLeft +",'" + closingId + "','" + openingId + "')", 33);
}
//]]>
</script>
اگرچه درک صحیح عملکرد این کد نیازمند تجربه نسبی و کار با جاوا اسکریپت است، اما بد نیست برای آگاهی بیشتر هم که شده، نگاهی اجمالی به کد بالا داشته باشیم.
توضیح:
- در قسمت متغیر contentHeight در ابتدای کد، ارتفاع بلاک محتوا را به پیکسل مشخص می کنیم، این همان بلاکی است که محتویات هر منو را در خود نمایش می دهد.
- در متغیر TimeToSlide میزان زمان (به میلی ثانیه) را برای شروع و پایان انیمیشن تعیین می کنیم، هر چه این زمان بیشتر باشد، سرعت انمیشن کندتر و میزان فرم های بیشتری ایجاد می شود (توصیه می شود مقادیر پیش فرض را تغییر ندهید).
- تابع runprobox در کد بالا، یک عدد به عنوان آرگومان می پذیرد، این عدد در واقع در هنگام فراخوانی تابع (که در ادامه خواهیم دید) برای هر بلاک متفاوت خواهد بود، به این ترتیب تابع قادر خواهد بود تا بلاک هدف را از سایر موارد شناسایی کند.
- setTimeout در توابع بالا نقش یک وقفه را بازی می کند، به این ترتیب که با فراخوانی تابع animate در زمان های متوالی، بین فرم ها وقفه های خیلی کوتاهی ایجاد می شود تا در نهایت حاصل کار به شکل یک انیمیشن به نمایش درآید.
- تابع animate نیز به عنوان موتور کد عمل کرده و با دریافت چهار آرگومان و بررسی آنها، در نهایت انیمیشن را خلق می کند، در این تابع متغیر curTick زمان فعلی، elapsedTicks میزان اختلاف بین آخرین اجرای تابع animate و زمان فعلی و متغیر opening و closing نیز مقادیر id بلاک هدف را در خود دارند.
- همان طور که ملاحظه می کنید تابع animate برای کنترل استایل و ویژگی های css بلاک ها از متد style و object استفاده می کند، به طور مثال opening.style.height ارتفاع بلاک opening را تعیین می کند یا closing.style.display نوع display بلاک closing را مشخص می کند.
نکته: این کد با وجود حجم بسیار کم، تقریبا با تمام مرورگرها سازگار است، از جمله اینترنت اکسپلورر 6 و مابعد، فایرفاکس، گوگل کروم، اپرا، سافاری و...

کد css منوی آکاردئونی


برای اینکه منوهای ما به درستی کار کنند، علاوه بر کد جاوا اسکریپت، به استایل css و کلاس های آن نیازمندیم، بدین منظور استایل زیر را نیز باید در صفحه خود وارد کنیم (به صورت یک فایل خارجی و یا به صورت درون صفحه ای).
<style type="text/css">
.proboxtitle, .proboxcontent, .proboxmain{
    position:relative;
}
.proboxtitle{
    width:200px;    
    height:25px;
    overflow:hidden;
    text-align:right;
    display:block;
    cursor:pointer;
    background-color:#666;
    color:#FFF;
    direction:rtl;
    padding:4px;
    text-align:center;
    border-bottom:1px dashed #CCC;    
}
.proboxcontent{
    width:200px;    
    height:auto;
    overflow:hidden;
    display:none;
    background-color:#F8F8F8;
    padding:4px;
    direction:rtl;
}
.proboxmain{
    border:1px solid #F0F0F0;
    width:208px;    
}
</style>
همان طور که ملاحظه می کنید، کد css بالا سه کلاس دارد که با آن، ویژگی ها و خواص ظاهری سه بلاک را در صفحه کنترل می کنیم، همچنین برخی موارد در استایل بالا قابل تغییر و برخی نیز به نحوه عملکرد برنامه مربوط بوده و غیر قابل تغییر هستند.

نحوه استفاده از منوی آکاردئونی


برای استفاده از کدهای بالا، در نهایت باید منو و باکس ها را در بلاک های div تعریف کنیم، برای نمونه مثال زیر می تواند راهنمای ما باشد.
<div id="proboxmain" class="proboxmain">
<!-- منوی شماره 1 -->
  <div class="proboxtitle" onclick="runprobox(1);">
  تیتر باکس 1
  </div>
  <div id="probox1content" class="proboxcontent">
  محتوای باکس آکاردئونی 1
  </div>
<!-- منوی شماره 2 -->  
  <div class="proboxtitle" onclick="runprobox(2);">
  تیتر باکس 2
  </div>
  <div id="probox2content" class="proboxcontent">
  محتوای باکس آکاردئونی 2
  </div>
<!-- منوی شماره 3 -->  
  <div class="proboxtitle" onclick="runprobox(3);">
  تیتر باکس 3
  </div>
  <div id="probox3content" class="proboxcontent">
  محتوای باکس آکاردئونی 3
  </div>
<!-- منوی شماره 4 -->  
  <div class="proboxtitle" onclick="runprobox(4);">
  تیتر باکس 4
  </div>
  <div id="probox4content" class="proboxcontent">
  محتوای باکس آکاردئونی 4
  </div>
</div>
توضیح:
- در مثال بالا، ابتدا یک بلاک اصلی با کلاس و آی دی proboxmain تعریف می کنیم، این بلاک تمام محتوای منوهای ما را در برمی گیرد.
- سپس برای هر منو، یک بلاک با کلاس proboxtitle و به همراه رویداد onclick تعریف می کنیم که تیتر منوها را در خود جای می دهد، این بلاک وظیفه فراخوانی تابع runprobox را دارد و یک عدد به عنوان آرگومان به تابع مذکور ارسال می کند، این عدد باید بین منوهای مختلف متفاوت و یکتا باشد تا برنامه بتواند بلاک مورد نظر را شناسایی کند.
- سپس در بلاک دیگری با آی دی و کلاس proboxcontent محتوای باکس خود را قرار می دهیم، در اینجا باید دقت کنید که برای آی دی،  بعد از عبارت probox عدد آرگومان را قرار داده و سپس عبارت content را اضافه کنید، به فرض اگر آرگومان تابع runprobox عدد 3 باشد، آی دی بلاک محتوا باید به صورت probox3content تنظیم شود.

مثال و پیش نمایش آنلاین


برای بررسی و تست برنامه، می توانید از مثال و پیش نمایش آنلاین زیر استفاده کنید.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>وبگو | باکس آکاردئونی با جاوا اسکریپت</title>
<!-- https://webgoo.ir -->
<style type="text/css">
body{
    font-family:Tahoma, Geneva, sans-serif;
    font-size:12px;
    direction:rtl;
}
.proboxtitle, .proboxcontent, .proboxmain{
    position:relative;
}
.proboxtitle{
    width:200px;    
    height:25px;
    overflow:hidden;
    text-align:right;
    display:block;
    cursor:pointer;
    background-color:#666;
    color:#FFF;
    direction:rtl;
    padding:4px;
    text-align:center;
    border-bottom:1px dashed #CCC;    
}
.proboxcontent{
    width:200px;    
    height:auto;
    overflow:hidden;
    display:none;
    background-color:#F8F8F8;
    padding:4px;
    direction:rtl;
}
.proboxmain{
    border:1px solid #F0F0F0;
    width:208px;    
}
</style>
<script type="text/javascript">
//<![CDATA[
var contentHeight = 34;
var TimeToSlide = 300.0;
var openprobox = '';
function runprobox(index){
    var divID = "probox" + index + "content";
    if(openprobox == divID){
        divID = '';
    }
    setTimeout("animate(" + new Date().getTime() + "," + TimeToSlide + ",'" + openprobox + "','" + divID + "')", 33);
    openprobox = divID;
}
function animate(lastTick, timeLeft, closingId, openingId){
    var curTick = new Date().getTime();
    var elapsedTicks = curTick - lastTick;
    var opening = (openingId == '') ? null : document.getElementById(openingId);
    var closing = (closingId == '') ? null : document.getElementById(closingId);
    
    if(timeLeft <= elapsedTicks){
        if(opening != null){
            opening.style.height = contentHeight + 'px';
        }
        if(closing != null){
            closing.style.display = 'none';
            closing.style.height = '0px';
        }
    return;
    }
    timeLeft -= elapsedTicks;
  var newClosedHeight = Math.round((timeLeft/TimeToSlide) * contentHeight);
  if(opening != null){
      if(opening.style.display != 'block'){
          opening.style.display = 'block';
      }
      opening.style.height = (contentHeight - newClosedHeight) + 'px';
  }
  if(closing != null){
      closing.style.height = newClosedHeight + 'px';
  }
  setTimeout("animate(" + curTick + "," + timeLeft +",'" + closingId + "','" + openingId + "')", 33);
}
//]]>
</script>
</head>
<body>
<noscript>
جاوا اسکریپت در مرورگر شما غیرفعال است یا پشتیبانی نمی شود!<br />
</noscript>

<div id="proboxmain" class="proboxmain">
<!-- منوی شماره 1 -->
  <div class="proboxtitle" onclick="runprobox(1);">
  تیتر باکس 1
  </div>
  <div id="probox1content" class="proboxcontent">
  محتوای باکس آکاردئونی 1
  </div>
<!-- منوی شماره 2 -->  
  <div class="proboxtitle" onclick="runprobox(2);">
  تیتر باکس 2
  </div>
  <div id="probox2content" class="proboxcontent">
  محتوای باکس آکاردئونی 2
  </div>
<!-- منوی شماره 3 -->  
  <div class="proboxtitle" onclick="runprobox(3);">
  تیتر باکس 3
  </div>
  <div id="probox3content" class="proboxcontent">
  محتوای باکس آکاردئونی 3
  </div>
<!-- منوی شماره 4 -->  
  <div class="proboxtitle" onclick="runprobox(4);">
  تیتر باکس 4
  </div>
  <div id="probox4content" class="proboxcontent">
  محتوای باکس آکاردئونی 4
  </div>
</div>
<hr />
برای بررسی ویژگی های منو، بر روی یکی از آیتم ها کلیک کنید.
</body>
</html>
پیش نمایش
دسته بندی: آموزش کاربردی » JavaScript
related مطالب بیشتر:
ساخت دکمه رفتن به بالای صفحه (Scroll to Top) با جاوا اسکریپت
ساخت پنل چند سربرگی (Tabbed Panel) با جاوا اسکریپت و CSS
نمایش کادر پیام شناور در سایت و وبلاگ با جاوا اسکریپت
اعتبارسنجی فرم های وب با جاوا اسکریپت (JavaScript)
استفاده ترکیبی از جاوا اسکریپت (JavaScript) و PHP
دیدگاه
more ۴۰ دیدگاه برای این مطلب ارسال شده است.
more چینش دیدگاه ها به ترتیب از جدیدترین به قدیمی ترین است.
نسرین خراشادی زاده
۲۰:۳۹ ۱۳۹۳/۰۸/۰۷
عالی بود خسته نباشید
۱۵:۵۸ ۱۳۹۳/۰۷/۱۶
ممنونم عالی بود
۰۱:۴۲ ۱۳۹۳/۰۴/۳۰
من کد ها رو توی فایل قرار میدم و همچیش هم درسته یعنی توی مرورگر کدها رم نشون میده اما وقتی سیو میکنم عمل نمیکنه! لطفا کمکم کنید
کدها را به روش مورد نظرتان (به صورت فایل ذخیره و آپلود شده در یک سرور) قرار داده، سپس اطلاع دهید تا بررسی کنیم.
۱۴:۳۲ ۱۳۹۳/۰۴/۲۹
اگه بخوام دو تا منو رو از همون اول باز نگه داره باید چیکار کنم؟!
<script type="text/javascript">
runprobox(1);
</script>
هرچی مقادیر به این کد اضاف کردم عمل نمیکرد
این کار با کد فعلی شدنی نیست، باید کد را به صورت اساسی دوباره نویسی کرد!
۱۲:۴۴ ۱۳۹۳/۰۴/۲۹
ببخشید که خیلی مزاحمتون میشم این سوالا یهو به ذهنم میرسه
چطوری میشه کاری کرد که بعد از کلیک کردن روی دکمه عکس پس زمینشم تغیر بکنه؟! مثلا که عکس پس زمینه به اسم باز و جمع هستش
ممنون میشم کمکم بکنید
برای این کار باید کمی جاوا اسکریپت بلد باشید، برای حالت باز و بسته دو کلاس css متفاوت تعریف کنید، زمانی که کاربر کلیک می کند، چک کنید ببینید کلاس باز فعال است یا بسته، اگر باز فعال بود، کلاس بسته را برای عنصر فعال کنید و برعکس، مثال:
<style type="text/css">
.open{
height:25px;
width:100px;
background:#C00;
}
.close{
height:25px;
width:100px;
background:#09F;
}
</style>
<script type="text/javascript">
function toggleDiv(id){
var elm = document.getElementById(id);
if(elm.className == 'open'){
elm.className = 'close';
}
else{
elm.className = 'open';
}
}
</script>
<div id="toggle" class="open" onclick="toggleDiv(this.id);">کلیک کنید</div>
۱۲:۰۲ ۱۳۹۳/۰۴/۲۹
مشکلم بر طرف شد!
خودم یه منو ساختم براش انگاری که استایل منوی قبلیم با این برنامه سازگار نبود فقط یه سوال
چطور میتونم کد ها رو با فرمت js سیو کنم و توی قالب فراخوانیش کنم!
چون الآن که این کار رو میکنم برنامه اجرا نمیشه
لطفا راهنمایی کنید
کدهای درون تگ script را در یک فایل متنی قرار داده، فایل را با فرمت js ذخیره نمائید یا فرمت txt را به js تغییر دهید، سپس فایل را در یک سرویس آپلود کرده و آدرس آن را به صورت زیر تنظیم نمائید:
<script type="text/javascript" src="http://yoursite.com/code.js"></script>
در نهایت این تکه کد را در قالب خود قرار دهید، قاعدتا نباید مشکلی باشد.
نکته: با درج آدرس فایل js در مرورگر باید محتوای آن نمایش داده شود، در غیر این صورت یا آدرس صحیح نیست یا سرور میزبان فایل دچار اشکالی است.
۱۱:۲۶ ۱۳۹۳/۰۴/۲۹
با سلام
من از این کد برای وبلاگم استفاده کردم و وقتی اجرا میکنم منو ها باید بسته باشند اما باز هستند!!!
یعنی هنوز کلیک نکرده باز هستن
وقتی هم که برای دفعه اول روش کلیک میکنی فکر مینکه بسته بوده، یعنی بسته نمیشه
وقتی هم که کدی رو که شما به دوستان گفتید بصورت پیشفرض باز میزاره رو گذاشتم الآن فهمیده که بازه و با کلیک اول بسته میشه.
لطفا بگید چطور میتونم کاری کنم که از همون اول بسته باشند
amir
۱۸:۳۸ ۱۳۹۳/۰۴/۲۳
سلام خیلی ممنون ولی چطور میشه از عمودی به افقی تغییر داد
به طور مثال جهت باز شدن این منو به صورت عمودی هستش چطور میشه افقی کرد جهت باز شدن رو
مرسی
سلام
ساده نیست! باید کدنویسی ها را کاملا ویرایش کرد و از مبنای height و width به left و right تغییر داد که زمانبر است و نیاز به آزمایش و خطای بسیار دارد!
ولی
۱۰:۴۱ ۱۳۹۳/۰۲/۰۳
سلام چطور میشه وقتی کلیک میکنیم رو به بالا باز شه
سلام
با توجه به فرم نوشته شدن کدها، این امکان به راحتی میسر نیست، اما با یک ترفند ساده می توانید این کار را به نحو دیگری شبیه سازی کنید:
بلاک div مربوط به تیتر را پائین تر از بلاک محتوا درج کنید.
SINA
۲۲:۱۶ ۱۳۹۲/۱۱/۲۹
تونستم با توی یک TABLE قرار دادن افقیشون کنم
من وقتی توی زیر منوها عکس میزارم فقط یک تیکه بالای عکس نشون داده میشه حالا چه کار کنم؟
تنظیم عکس با استفاده از خاصیت های CSS امکانپذیر است، باید با این امکان آشنا باشید.
SINA
۱۰:۲۵ ۱۳۹۲/۱۱/۲۴
نمیشه شما بگید کجا رو عوض کنم تا افقی بشه چون من خیلی CSS بلد نیستم
متاسفانه خیر، این کار نیاز به تغییر استایل CSS از مبنا و آزمایش و خطا دارد که کاری وقتگیر است.
SINA
۱۹:۰۹ ۱۳۹۲/۱۱/۲۳
چطوری میتونم باکس ها را افقی کنم
به نظر با CSS قابل حل است، باید مسلط باشید!
علی
۲۳:۰۲ ۱۳۹۲/۱۱/۰۲
با سلام ممنون از آموزش هایتان وقتی کد پیام بلاگ را به بلاگفا می ریزم ارور (امکان درج عبارت payamblog.js در قالب وبلاگ وجود ندارد) را می دهد و وقتی این آدرس را پاک می کنم جدول بندی وبلاگم بهم می خورد چکار کنم لطفا راهنمائی کنید.
سلام
این مشکل تنها با تغییر نام فایل (یا فایل ها) و آپلود آن در یک سرویس دیگر (و ایجاد کد جدید) قابل حل است.
۲۰:۲۴ ۱۳۹۲/۰۹/۲۴
سلام! ممنون از زحماتتون و اینکه وقت میزارید و به سوالات کاربران پاسخ میدید...
میخواستم بدونم چطوری میشه تعداد باکس ها رو از 4 تا افزایش داد ممنون
سلام
به صورت نمونه زیر می توانید هر تعداد بخواهید باکس اضافه کنید:
<!-- منوی شماره 4 -->  
<div class="proboxtitle" onclick="runprobox(4);">
تیتر باکس 4
</div>
<div id="probox4content" class="proboxcontent">
محتوای باکس آکاردئونی 4
</div>
<!-- منوی شماره 5 -->
<div class="proboxtitle" onclick="runprobox(5);">
تیتر باکس 5
</div>
<div id="probox5content" class="proboxcontent">
محتوای باکس آکاردئونی 5
</div>
سحر
۱۰:۴۵ ۱۳۹۲/۰۹/۱۸
با تشکر فراوان به خاطر آموزش.چطور می توانیم منوی اول را پیش فرض باز نمایش دهیم؟
سلام
برای این کار کافی است در انتهای کدهای منو، کد زیر را قرار دهید:
<script type="text/javascript">
runprobox(1);
</script>
more لطفا پیش از ارسال دیدگاه نکات زیر را مد نظر داشته باشید:
- به سوالات کلی، زمانبر، مبهم و مشکلاتی که تلاشی برای رفع آنها نکرده باشید پاسخ مختصر داده شده یا به بخش برنامه نویسی اختصاصی ارجاع داده می شوند.
- کدها و اسکریپت های طولانی را ترجیحا در یک صفحه وب آنلاین یا به صورت حساب موقت و آزمایشی قرار دهید تا امکان بررسی دقیق مشکل و خطایابی میسر باشد.
- تمام دیدگاه های ارسالی خوانده شده و برای هر کاربر مدت زمان لازم جهت پاسخگویی در نظر گرفته می شود، لطفا از طرح سوالات متعدد در بازه زمانی کوتاه خودداری کنید.



 refresh
10 × 10
8 × 8
20 × 20
=