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

ساخت منوها و باکس های آکاردئونی (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
برچسب ها: CSS - JavaScript

اعتبارسنجی فرم های وب با جاوا اسکریپت (JavaScript)
نمایش کادر پیام شناور در سایت و وبلاگ با جاوا اسکریپت
ساخت پنل چند سربرگی (Tabbed Panel) با جاوا اسکریپت و CSS
چگونه لوگوی حمایتی برای نمایش در سایت یا وبلاگ بسازیم؟
کنترل و تغییر اندازه فونت صفحه با جاوا اسکریپت
دیدگاه


۲۰:۲۲ ۱۳۹۲/۰۹/۰۸
واقعا از سایتتون ممنونم کارم رو تو بد شرایطی راه انداخت
۱۶:۱۹ ۱۳۹۲/۰۵/۰۳
بسیار ساده و مفید بود ، ممنونم
ابوالفضل
۰۳:۵۹ ۱۳۹۲/۰۴/۱۹
با سلام
آیا می شه کاری کرد زمانی که بر روی منو باز شده کلیک شد بسته نشود و فقط با انتخاب گزینه های دیگه بسته شود منو. به طور کلی نمی خوام زمانی که روی یک منو کلیک کردیم و باز شد با کلیک مجدد بسته شود؟!
ممنون میشم راهنمایی بفرمایید ...
آیا می شه کاری کرد زمانی که بر روی منو باز شده کلیک شد بسته نشود و فقط با انتخاب گزینه های دیگه بسته شود منو. به طور کلی نمی خوام زمانی که روی یک منو کلیک کردیم و باز شد با کلیک مجدد بسته شود؟!
ممنون میشم راهنمایی بفرمایید ...
سلام
بله، قسمت زیر را در کد پیدا کنید:
بله، قسمت زیر را در کد پیدا کنید:
if(openprobox == divID){
divID = '';
}
در تابع runprobox مشخص است، سپس آن را به صورت زیر تغییر دهید: if(openprobox == divID){
divID = '';
return false;
}
الهه
۱۴:۳۰ ۱۳۹۲/۰۴/۰۹
ممنون از وقتی که برای من گذاشتین و پاسخ دادین.
الهه
۱۶:۰۴ ۱۳۹۲/۰۴/۰۶
سلام و ممنون از سایت خوبتون.
الان با رفرش صفحه محتویات هر چهار منو نمایش داده نمیشه و باید روشون کلیک کرد. چطور میشه کاری کرد که با رفرش صفحه محتویات یک منوی خاص به صورت پیش فرض نمایش داده بشه؟
ممنون!
الان با رفرش صفحه محتویات هر چهار منو نمایش داده نمیشه و باید روشون کلیک کرد. چطور میشه کاری کرد که با رفرش صفحه محتویات یک منوی خاص به صورت پیش فرض نمایش داده بشه؟
ممنون!
سلام
برای این کار کافی است در انتهای کدهای منو، کد زیر را قرار دهید:
برای این کار کافی است در انتهای کدهای منو، کد زیر را قرار دهید:
<script type="text/javascript">
runprobox(1);
</script>
فرناز
۱۱:۴۶ ۱۳۹۱/۱۲/۲۳
1 - ارتفاع باکس تغییر نمی کنه با اینکه وقتی چند دسته قرار میدم خیلی بیشتر از این ارتفاع داره و اونو کامل نشون میده
2 - من زیر منو ها رو اینطور اضافه کردم
2 - من زیر منو ها رو اینطور اضافه کردم
<div id="proboxmain" class="proboxmain">
<!-- منوي شماره 1 -->
<div class="proboxtitle" onclick="runprobox(1);">
درباره ما
</div>
<div id="probox1content" class="proboxcontent">
سيماي استان
</div>
<div id="probox1content" class="proboxcontent">
اساسنامه
</div>
ولی فقط سیمای استان نمایش داده میشه ....نحوه استفاده از کد اشتباه است!
اگر به مثال توجه کنید، هر منو یک شماره متناظر دارد که در دو قسمت runprobox و آی دی بلاک محتوا استفاده می شود تا منوهای متفاوت از هم تفکیک شوند.
برای نمایش محتوای بیشتر مقادیر متغیر contentHeight را افزایش داده و داخل هر بلاک محتوا به صورت نمونه زیر از بلاک های زیر مجموعه استفاده کنید:
اگر به مثال توجه کنید، هر منو یک شماره متناظر دارد که در دو قسمت runprobox و آی دی بلاک محتوا استفاده می شود تا منوهای متفاوت از هم تفکیک شوند.
برای نمایش محتوای بیشتر مقادیر متغیر contentHeight را افزایش داده و داخل هر بلاک محتوا به صورت نمونه زیر از بلاک های زیر مجموعه استفاده کنید:
<!-- منوی شماره 1 -->
<div class="proboxtitle" onclick="runprobox(1);">
تیتر باکس 1
</div>
<div id="probox1content" class="proboxcontent">
<div class="sub_1">
محتوای باکس آکاردئونی 1-1
</div>
<div class="sub_2">
محتوای باکس آکاردئونی 1-2
</div>
<div class="sub_3">
محتوای باکس آکاردئونی 1-3
</div>
</div>
فرناز
۱۲:۲۷ ۱۳۹۱/۱۲/۲۲
سلام خسته نباشید
واقعا ممنون از آموزش هاتون
من که خیلی استفاده کردم
من چند مشکل دارم ممنون میشم راهنماییم کنین...
1 - چطور طول منو را زیاد کنم ؟ چون با این طولی که داره بیشتر از 5 منو رو نشون نمیده
2 - چطور در زیرمنوها چند گزینه قرار بدم چون با اینکه من چند تا زیر منو گذاشتم ولی یکی بیشتر نشون نمیده
3 - چطور به زیر منوها لینک بدم که به دسته مشخص خودشون ارجاع داده بشن ....
ممنون از همکاریتون .....
واقعا ممنون از آموزش هاتون
من که خیلی استفاده کردم
من چند مشکل دارم ممنون میشم راهنماییم کنین...
1 - چطور طول منو را زیاد کنم ؟ چون با این طولی که داره بیشتر از 5 منو رو نشون نمیده
2 - چطور در زیرمنوها چند گزینه قرار بدم چون با اینکه من چند تا زیر منو گذاشتم ولی یکی بیشتر نشون نمیده
3 - چطور به زیر منوها لینک بدم که به دسته مشخص خودشون ارجاع داده بشن ....
ممنون از همکاریتون .....
سلام
در مورد سوال اول، اگر منظور از طول، ارتفاع باکس است، این کار با افزودن باکس های بیشتر به صورت خودکار انجام می شود و نیاز به تغییر مورد خاصی نیست، اگر منو نمایش داده نمی شود، ممکن است به دلیل ارتفاع محدود بلاک های دیگری باشد که باکس منو را داخل آنها استفاده کرده اید.
در مورد سوال دوم و اینکه چند گزینه در زیرمنوها قرار دهید، البته این نوع منو محدودیت هایی از این لحاظ دارد، اما با افزایش مقدار var contentHeight و درج و تنظیم بلاک های div بیشتر داخل بلاک های proboxcontent می توان موارد مورد نظر را ایجاد کرد (نیاز به آشنایی و تسلط نسبی با html و طراحی وب دارد).
برای مورد آخر نیز محدودیتی وجود ندارد، می توانید از تگ a و href در محتوای داخل زیرمنوها برای ایجاد لینک استفاده کنید.
در مورد سوال اول، اگر منظور از طول، ارتفاع باکس است، این کار با افزودن باکس های بیشتر به صورت خودکار انجام می شود و نیاز به تغییر مورد خاصی نیست، اگر منو نمایش داده نمی شود، ممکن است به دلیل ارتفاع محدود بلاک های دیگری باشد که باکس منو را داخل آنها استفاده کرده اید.
در مورد سوال دوم و اینکه چند گزینه در زیرمنوها قرار دهید، البته این نوع منو محدودیت هایی از این لحاظ دارد، اما با افزایش مقدار var contentHeight و درج و تنظیم بلاک های div بیشتر داخل بلاک های proboxcontent می توان موارد مورد نظر را ایجاد کرد (نیاز به آشنایی و تسلط نسبی با html و طراحی وب دارد).
برای مورد آخر نیز محدودیتی وجود ندارد، می توانید از تگ a و href در محتوای داخل زیرمنوها برای ایجاد لینک استفاده کنید.
نگین
۲۳:۴۰ ۱۳۹۱/۱۱/۱۶
ببخشید چه طوری میشه کاری کرد که حهت باز شدن منو برعکس بشه؟
سلام
برای این کار کافی است بلاک های div مربوط به محتوا را پیش از بلاک های مربوط به تیتر قرار دهید.
برای این کار کافی است بلاک های div مربوط به محتوا را پیش از بلاک های مربوط به تیتر قرار دهید.
reza
۰۹:۳۹ ۱۳۹۱/۰۸/۱۵
سلام ، خسته نباشید
چطور میشه محتویات منوی auto کرد یعنی به اندازه محتویات باز بشه ؟
چطور میشه محتویات منوی auto کرد یعنی به اندازه محتویات باز بشه ؟
سلام
این مورد را بررسی نکرده ایم، ولی به نظر می رسد برای انجام این کار باید تغییراتی اساسی در نحوه عملکرد کد ایجاد کنید، چرا که برنامه از مقادیر عددی برای محاسبه تعداد فرم های انیمیشن در متغیر contentHeight استفاده می کند و عملیات ریاضی مانند ضرب نیز در ادامه آن وجود دارد، از طرفی این نوع منوها معمولا برای موارد استاتیک استفاده می شوند.
این مورد را بررسی نکرده ایم، ولی به نظر می رسد برای انجام این کار باید تغییراتی اساسی در نحوه عملکرد کد ایجاد کنید، چرا که برنامه از مقادیر عددی برای محاسبه تعداد فرم های انیمیشن در متغیر contentHeight استفاده می کند و عملیات ریاضی مانند ضرب نیز در ادامه آن وجود دارد، از طرفی این نوع منوها معمولا برای موارد استاتیک استفاده می شوند.
hosin
۱۳:۴۵ ۱۳۹۱/۰۸/۰۵
ممنون از آموزش هاتون
- به سوالات کلی، زمانبر، مبهم و مشکلاتی که تلاشی برای رفع آنها نکرده باشید پاسخ مختصر داده شده یا به بخش برنامه نویسی اختصاصی ارجاع داده می شوند.
- کدها و اسکریپت های طولانی را ترجیحا در یک صفحه وب آنلاین یا به صورت حساب موقت و آزمایشی قرار دهید تا امکان بررسی دقیق مشکل و خطایابی میسر باشد.
- تمام دیدگاه های ارسالی خوانده شده و برای هر کاربر مدت زمان لازم جهت پاسخگویی در نظر گرفته می شود، لطفا از طرح سوالات متعدد در بازه زمانی کوتاه خودداری کنید.