Accordion API 與教學文件參考 :
# https://jqueryui.com/accordion/
# http://api.jqueryui.com/accordion/
本篇測試參考了如下書籍 :
- jQuery UI 使用者介面設計 (歐萊里, Studio Tib. 譯)
- jQuery UI 與 Plugin 開發實戰 (悅知文化, 吳哲穎譯)
- jQuery 全能權威指南 (上奇, 張亞飛)
- Pro jQuery 2.0 2nd ed. (Apress, Freeman Adam)
- jQuery UI in Action (Manning, TJ Vantoll)
- jQuery 應用程式設計極速上手 (上奇, 羅友志譯)
- 打造 jQuery 網頁風暴 (張子秋, 佳魁)
# jQuery UI 學習筆記 (四) : 頁籤面板 (Tabs)
折疊選單的網頁架構與頁籤面板一樣也是使用兩層 div 套疊, 它們的外層 div 元素只是個殼, 內層的 div 元素才是放內容的容器. 兩者在結構上的差別是, 頁籤面板使用 ul-li 元素建構頁籤, 而折疊選單則用 p 或 h1~h6 元素建構標題; 在功能上頁籤面板支援使用 Ajax 動態載入內容, 而折疊選單則不支援.
下面是一個三列折疊選單的網頁結構, 使用 h2 包覆標題內容 (其實不管是使用 h1~h6 哪一個元素, 標題的字大小都一樣) :
<div id="accordion">
<h2>第 1 列標題</h2>
<div>第 1 列內容</div>
<h2>第 2 列標題</h2>
<div>第 2 列列內容</div>
<h2>第 3 列標題</h2>
<div>第 3 列內容</div>
</div>
然後在 Javascript 程式碼中取得外層 div 元素後呼叫 accordion() 即可 :
$("accordion").accordion();
例如 :
測試 1 : 折疊選單結構測試 (1) [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2>第 1 列標題</h2>
<div id="row1">第 1 列內容</div>
<h2>第 2 列標題</h2>
<div id="row2">第 2 列內容</div>
<h2>第 3 列標題</h2>
<div id="row3">第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion();
});
</script>
</body>
</html>
結果如下 :
除了使用 h1~h6 元素外, 也可以用 p 元素來包覆標題內容 :
<div id="accordion">
<p>第 1 列標題</p>
<div id="row1">第 1 列內容</div>
<p>第 2 列標題</p>
<div id="row2">第 2 列列內容</div>
<p>第 3 列標題</p>
<div id="row3">第 3 列內容</div>
</div>
例如下列範例 2 :
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<p>第 1 列標題</p>
<div>第 1 列內容</div>
<p>第 2 列標題</p>
<div>第 2 列列內容</div>
<p>第 3 列標題</p>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion();
});
</script>
</body>
</html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<p>第 1 列標題</p>
<div>第 1 列內容</div>
<p>第 2 列標題</p>
<div>第 2 列列內容</div>
<p>第 3 列標題</p>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion();
});
</script>
</body>
</html>
也可以使用 div 元素包覆標題內容 :
<div id="accordion">
<div>第 1 列標題</div>
<div>第 1 列內容</div>
<div>第 2 列標題</div>
<div>第 2 列內容</div>
<div>第 3 列標題</div>
<div>第 3 列內容</div>
</div>
效果如下列範例 3 所示 :
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<div>第 1 列標題</div>
<div>第 1 列內容</div>
<div>第 2 列標題</div>
<div>第 2 列內容</div>
<div>第 3 列標題</div>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion();
});
</script>
</body>
</html>
不過有些書的範例是將標題內容先用 a 元素包覆後再用 h1~h6 或 p 元素包覆 :
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
注意, 超連結 a 元素的 href 屬性須用 "#" (表示沒有連外).
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion();
});
</script>
</body>
</html>
內容有用 a 元素包覆的效果與沒有的看似差不多, 但仔細看還是有差異, 沒有 a 元素的標題在開啟後總是會有黑邊框; 而有 a 元素的則幾乎沒有. 官網範例沒有先用 a 元素包覆.
以上範例在呼叫 accordion() 時沒有傳入參數, 這樣會以預設值 (例如開啟第一列標題等) 初始化折疊選單, 進階用法可以傳入一個選項物件來進行設定, 常用的選項物件屬性如下表 :
常用設定屬性 | 說明 |
active | 預設開啟之標題索引 (0 起始, 預設 0), 亦可為 true/false, 參考 collapsible |
aninmate | 展開/收合時之動畫設定, true=有動畫, false=無動畫, 或用數值設定毫秒數 |
collapsible | 是否可收合 (預設 false), 當 true 時, 若 active=false 則全部收合 |
disabled | 是否將折疊選單禁能 true/false (預設) |
heightStyle | 內容高度 : auto (自動, 預設), fill (與父元素同高), content (與內容同高) |
event | 設定開啟標題之事件 (click 或 mouserover 等), 預設為 "click" (按滑鼠左鍵) |
設定選項語法如下 :
$("#accordion").accordion({option1: value1, option2: value2, .....})
$("#accordion").accordion("option", 屬性名稱, 屬性值) //settet : 設定選項屬性之值
如果沒有傳入屬性值則傳回該屬性之值 :
var value=$("#accordion").accordion("option", 屬性名稱) //getter : 傳回選項屬性之值
網頁載入時折疊選單預設是開啟索引為 0 的第一個標題, 下面範例則是指定初始化時開啟索引為 1 的第二個標題 :
測試 5 : 初始化時開啟指定之標題 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion({active: 1});
});
</script>
</body>
</html>
效果如下 :
折疊選單預設只有一個標題會開啟其內容, 如果想關閉此功能, 讓其初始化時全部標題都收合, 則必須用 {active: false, collapsible: true} 去設定, 例如 :
測試 5-1 : 初始化時全部標題都收合 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion({active: false, collapsible: true});
});
</script>
</body>
</html>
結果如下 :
heightStyle 屬性預設為 "auto", 表示會依據內容自動調整高度, 但那是對內容本來就寫在 div 元素中的情況, 但若內容是網頁載入後用 Javascript 程式動態寫入 DOM 者來說就無效, 標題展開時不會完全打開內容容器, 解決辦法是將其設定為 "content", 表示是依據實際的內容調整容器高度 :
$("#accordion").accordion({heightStyle: "content"});
參考 :
# https://stackoverflow.com/questions/6369241/jquery-accordion-height
例如 :
測試 6 : 設定內容高度依據實際資料自動調整 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion();
console.log($("#accordion").accordion("option", "heightStyle")); //輸出 "auto"
$("#accordion").accordion("option", "heightStyle", "content");
console.log($("#accordion").accordion("option", "heightStyle")); //輸出 "content"
});
</script>
</body>
</html>
此處使用 option 方法先查詢 heightStyle 選項屬性之值, 可知預設為 auto, 然後再用 option 方法將其設定為 content. 這個設定的效果要動態地載入較長內容時才觀察得到.
折疊選單預設是用滑鼠點擊事件 (click) 來觸發標題之展開, 可以用 event 選項屬性來更改或添加所綁定之事件, 若有多個事件中間用空格隔開 :
$("#accordion").accordion({event: "mouseover"});
例如 :
測試 7 : 設定標題開啟收合之觸發事件 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion({event: "mouseover"});
});
</script>
</body>
</html>
可見只要滑鼠移到標題上面, 其內容就會展開了.
屬性選項 animate 可以控制標題展開收合時是否要套用動畫, 其值可以是布林值 true/false (預設 true); 也可以是毫秒為單位的整數, 下面範例是將 animate 設為 false 關掉動畫效果 :
測試 8 : 取消動畫效果 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion({animate: false});
});
</script>
</body>
</html>
可見展開與收合時的動畫效果消失了. 下面範例則是使用滑桿元件控制動畫毫秒數, 關於滑桿之操作參考 :
# jQuery UI 學習筆記 (六) : 滑桿 (Slider)
測試 9 : 以滑桿控制動畫速度 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="hslider" style="width:300px;"></div><br>
<div id="accordion">
<h2><a href="#">第 1 列標題</a></h2>
<div>第 1 列內容</div>
<h2><a href="#">第 2 列標題</a></h2>
<div>第 2 列內容</div>
<h2><a href="#">第 3 列標題</a></h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
$("#accordion").accordion();
$("#hslider").slider({
min: 0,
max: 500,
create: function(e, ui) {
var style={"width":"30px","text-align":"center"};
$(this).find(".ui-slider-handle").css(style);
},
slide: function(e, ui) {
$(this).find(".ui-slider-handle").html(ui.value);
$("#accordion").accordion("option", "animate", ui.value); //動態設定動畫毫秒數
}
});
});
</script>
</body>
</html>
用搖桿調整動畫時間 (0~500 ms), 調到 0 時就沒動畫效果了.
雖然折疊選單與頁籤面板很類似, 但很可惜的是折疊選單沒有像頁籤面板那樣可用 Ajax 動態地從遠端載入內容的功能, 但可以透過 activate 事件來達成這個目的, 參考 :
# How to load content in jQueryUI accordion dynamically
這個解決方案的原理就是利用 ui.newHeader 集合取得子元素 a 的 href 屬性, 然後透過 Ajax 功能取得遠端資源後呼叫 html() 將其寫進放內容的 div 元素容器裡, 所以網頁必須使用上面範例 4 的用 a 元素包覆標題的結構才行, 如下面範例所示 :
測試 11 : 利用 activate 事件實現 Ajax 動態更新內容 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<div id="accordion">
<h2><a href="ajax1.htm">第 1 列標題</a></h2>
<div>載入中 ...</div>
<h2><a href="ajax2.htm">第 2 列標題</a></h2>
<div>載入中 ...</div>
<h2><a href="ajax3.php">第 3 列標題</a></h2>
<div>載入中 ...</div>
</div>
<script>
$(function(){
$("#accordion").accordion({
heightStyle: "content",
activate: function (e, ui) {
url=$(ui.newHeader[0]).children('a').attr('href');
$.ajax({
method: "GET",
url: url,
cache: false,
success: function (data) {
$(ui.newHeader[0]).next().html(data);
}
});
}
});
});
</script>
</body>
</html>
此網頁中折疊選單的三個標題都用 a 元素連結遠端資源, 分別是 ajax1.htm, ajax2.htm, 與 ajax3.php, 前面兩個網頁內容都是簡單的 p 元素包覆的檔名, 分別是 :
<p>ajax1.htm</p> 與
<p>ajax2.htm</p>
為了測試動態內容, ajax3.php 會回應後端伺服器的當地時間 :
<?php
echo date("Y-m-d H:i:s");
?>
其次我將原參考網頁使用的 $.get() 改成 jQuery 底層函數 $.ajax(), 因為它有較多屬性可設定, 此處是為了取消瀏覽器的 cache 功能, 參考 :
# Prevent browser caching of AJAX call result
關於 $.ajax() 用法參考 :
# 測試 jQuery 的 Ajax 函數 $.ajax()
結果如下 :
實際測試可知, 使用 activate 事件屬性確實能動態地從遠端取得資料後更新內容, 此方法彌補了 jQuery UI 未替 Accordion 內建 Ajax 功能之缺憾.
折疊選單的 API 並沒有提供動態新增一組面板 (標題+內容) 的方法, 但可以利用 jQuery 的 append() 方法以及 Accordion 元件的 refresh 方法來達成, 這是我在參考書目 5 (jQuery UI in Action) 這本書中找到的做法, 改編如下 :
測試 11 : 利用 append() 與 refresh 方法動態新增一組面板 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size:10px;
}
</style>
</head>
<body>
<label for="new_title">新標題</label>
<input type="text" id="new_title" value="新標題"><br>
<label for="new_content">新內容</label>
<input type="text" id="new_content" value="新內容">
<button id="add">新增</button><br>
<div id="accordion">
<h2>第 1 列標題</h2>
<div>第 1 列內容</div>
<h2>第 2 列標題</h2>
<div>第 2 列內容</div>
<h2>第 3 列標題</h2>
<div>第 3 列內容</div>
</div>
<script>
$(function(){
var accordion=$("#accordion").accordion();
$("#add").button();
$("#delete").button();
$("#add").on("click", function(e){
e.preventDefault();
var new_item="<h2>" + $("#new_title").val() + "</h2>" +
"<div>" + $("#new_content").val() + "</div>";
accordion.append(new_item).accordion("refresh");
});
});
</script>
</body>
</html>
此例將要新增的面板 (標題+內容) 傳給 append() 方法, 接著鏈式呼叫 refresh 方法更新摺疊選單外觀, 結果如下 :
輸入新面板的標題與內容後按新增鈕, 就會在底下新增一組面板了.
沒有留言:
張貼留言