此篇文件主要是針對 Bootstrop 5 的手風琴 (Accordion) 元件與 JavaScript 的 Vanilla JS 撰寫風格進行一些應用上與觀念上的記錄。

Bootstrop 5 與 Vue.js 也都同樣採 Vanilla JS 撰寫風格進行開發,在 Bootstrap 5 的部份也因不再依於 jQuery 的函式庫,因此需要對 JavaScript 原生寫法與原理進行了解。


手風琴 (Accordion) 元件相關官方文件

BS-v5 手風琴 (Accordion) 元件相關文件,連結如下:

如果外語能力不錯,可以看日文版的 Bootstrap 5 文件,連相關版別更動都有記錄,會以開發尋除錯應用會更清楚。


手風琴 (Accordion) 元件的以 html 標籤屬性與結構建立靜態功能

引入 Bootstrap 5 版的確任方式與 bootstrap.js 物件

這裡以英文文件為主,在 20211103 的期間版別為 5.0.2,分別針對 CSS 與 JS 打包插件引入 HTML 結構中。

確任 Bootstrap 是否引入,可使用 console.log('bootstrap', bootstrap); 查看。
另外在瀏覽器開發者工具輸入 bootstrap 查看 JS 是否引入成功,若成功會得到一個 bootstrap 物件,此時的 bootstrap 是在瀏覽器的全域環境之下。

展開物件,會看些屬性名稱與值,名稱的部份會是 Bootsrap 的相元件名,屬性會是 class X {} 的 JavaScript 類別 (class),對於 JavaScript 類別 (class) 的部份不是很熟,大約的概念是先裡面如以呼叫到許多對應的函式來應用。

這一段不是要來說細說原生 JS 與 bootstrap.js 打包後的架構與觀念,這裡只是要說明成功引入 bootstrap JS 相關功能與等一下會手風琴 (Accordion) 元件會使用到的折疊 (Collapse),而截圖中可以見到 Collapse: class et { constructor(e, i) } 這個 bootstrap 物件下的屬性。

更多觀念參考文:[教學] 深入淺出 JavaScript ES6 Class (類別)

手風琴 (Accordion) 元件靜態功能

確任好 bootstrap.js 於瀏覽器中載入成 bootstrap 物件後,在 HTML 中加入手風琴 (Accordion) 文件範例裡的 HTML 靜態結構。


codesandbox 此時就可將元件進行操作,先前確任 bootstrap 物件載的的部份,也可以在 console 面版中查到 bootstrap 物件,此時可見到三個區塊可分別於 Accordion Item #x 的按鈕點按下進行互動操作。

手風琴 (Accordion) 元件 html 標籤屬性

以下在元件中使用 Accordion Item #1 做為說明。

最外層元素對象

手風琴 (Accordion) 元件透過 id="collapseOne" 最外層元素,做為唯一收閤區塊的指定元素。

透過 HTML 標中屬性以資料屬性來操作,主要是由 控制元素 去操作 對象元件class='' 中加入 .show 樣式,官方文件說明如下:

只需將 data-bs-toggle="collapse" 以及 data-bs-target 加入元素即可自動指定控制一個或多個可折疊元素。 data-bs-target 屬性接受 CSS 選擇器以套用摺疊。請確保有在可折疊元素上添加 collapse 類別。如果希望它預設是打開的,加上額外的類別 .show
如果要在一個可折疊區域加入可折疊群組,加入 data-bs-parent="#selector" 資料屬性。可以參考範例中的效果。

data-bs-x 控制元素標籤屬性

data-bs-parent=”#accordionExample” 在操作控制元素下決定要呈現的唯一收閤區塊

id="collapseOne" 最外層元素下,配合著每個 Accordion Item #x 控制元素裡的標籤屬性 data-bs-parent="#accordionExample" 指定,在進行點按時才可做為唯一區塊的呈現。

data-bs-toggle=”collapse”

data-bs-toggle="collapse":使用 bootstrap.js 的裡的折疊 (Collapse) 元件功能,所對應的會是 bootstrap.Collapse 屬性 (或建構功能方式)。

data-bs-target=”#collapseOne”

data-bs-target="#collapseOne":使用 Bootstrap 折疊 (Collapse) 元件功能時,所操作的對象是 手風琴 (Accordion) 元件中的 id="collapseOne" 元素對象。

aria-x 無障礙相關標籤

在 Bootstrap.js 中以 JavaScript 進行規劃下,基本上是用不到,之後為了於 JS 功能說明時會移除,這裡主要只有文件下取範例程式碼結構說明。


手風琴 (Accordion) 元件以 bootstrap.js 與 JavaScript 建構功能

JS 陣列方法 .map() 取得 DOM 元素,將多個操作對象集合進陣列 (收閤 collapse 區塊)

以 JavaScript 建構功能在文件中的折疊 (Collapse) 元件範例來說,是先取 DOM 元素做為操作目標。

上面的文件範例程式碼,主要是要直接用 JS 陣列方法 .map() 在執行後直接產生一個陣列資料,將處理完 bootstrap.Collapse 物件集合到 collapseList 變數中。

但為何不直接針對 document.querySelectorAll('.collapse') 集合到 collapseList 變數中呢?

直接使用 document.querySelectorAll('.collapse') 的話取得的是一個類陣列 ( NodeList) 集合,裡面不會有 .map() 的陣列方法,所能使用的方法也較少。

但透過 [].slice.call() 方法產生一個 Array 純陣列物件資料,將 document.querySelectorAll('.collapse') 的結構先複制進記憶體中做轉化處理,除了可降低瀏覽器相容性問題外,在純陣列中的方法也比類陣列還多,透過這樣的方式也可省下不少的程式碼撰寫。

DOM 元素對象透過 bootstrap.js 建構式,配合 new 方式處理成 Collapse 物件並集合於陣列

new bootstrap.Collapse() 指定元素對象逐一產生出 collapse 物件 (沒相關設定預設選項)

產生完 Array 純陣列,針對陣列取得每筆 .collapsed 樣式名稱節點位置,將結果賦予到 collapseElementList 變數之上。

collapseElementList 變數內函著每個節點位置,可以透過瀏覽器開發者工具,再變數後方加上 [<索引位置數值>] 取得 (起始位置是 0) 就可取得。

collapseElementList 透過陣列方法 .map() 執行,會將每個陣列中的節點透過方法中的參數 collapseElnew bootstrap.Collapse() 建構式的方式,建立出一個 bootsrap.js 的 Collapse 物件,在所有 .map() 陣列方法執行完成後,會把所有的 Collapse 物件同樣以陣列集結到 collapseList 變數中,如果要同樣取得加入 bootsrap.js 的 Collapse 功能的 Collapse 物件。

同樣和前面集合收閤 DOM 元素的陣列變數 collapseElementList,也是在開發者工具下輸入變數 collapseList 加上使用 [<索引位置數值>],就可取得對應的 Collapse 物件,例如要取得第一個收閤區塊只要 collapseList[0] 就可取得。
展開 collapseList[0] 第一個收閤區塊,也就是由 bootstrap.js 建構出的 Collapse 物件的第一個收閤元素,會發現下面的結構。

但是,會覺得怪怪的,為何畫面上第一個收閤會是關閉著,而下面的都是展開的呢?
此外直接針對手風琴 (Accordion) 元件內的收閤項目操作,會發現沒有和 HTML 靜態結構一樣,是以唯一區塊呈現。

將指定元素對象的 collapse 物件,設定選項 toggle: false 修正畫面呈現第一收閤與之後都展開

查找 bootstrap collapse 文件的方法 (methods),在方法 (methods) 中,加入設定來修正此問題,猜主要會是 toggle 設定,加入此方法設定看看。

加入 { toggle: false } 選項設定為 false,結果與 HTML 所型成的靜態結構與畫面呈現是一樣的。

補充說明:
bootstrap.Collapse(){ toggle: false } 設定,以口語化的方式是指 這個 bootstrap.Collapse() 物件對象裡的 toggle 功能不啟用
collapse 物件裡,第一個參數指定是設有 collapse 功能的元素對象,在預設第二個參數沒寫是直接以 { toggle: true } 設定啟用。

但還是有問題,在手風琴 (Accordion) 元件內唯一收閤 Collapse 的區塊,還是無法啟用,但在 HTML 結構中也確任有加上了 data-bs-parent="#accordionExample" 針對操作對象元素 id="accordionExample" 在 HTML Tag 的屬性中,但確沒有作用,在各自的控制區塊點按時還是各自收閤…

將指定元素對象的 collapse 物件,選項多加入 parent 設定,修正收閤無法有唯一展以各自展開切換操作

重新開啟瀏覽器開發者工具,在輸入 collapseList[0] 查看第一個收合結構的 Collapse 物件,展開物件查看發現 _parent: null,與 _config: {toggle: false, parent: ""},由此大約可得知 Collapse 物件並沒有對於手風琴元件的對象元素 id="accordionExample" 進行指定。

再查找了 Bootstrap 文件 > 選項裡 的表格內容如下:

如果加入了 parent,則當可折疊物件為顯示時,指定父項下的所有可折疊元素將被關閉。… 該屬性必須在目標可折疊區域上設置。

文件表格中的 type selector | jQuery object | DOM element 指的就是 data-bs-parent="" 設定為被指定為對象元素 id="accordionExample"
白話一點就是指 bootstrap.Collapse() 在第二個參數就是選項,是以 {} 中以屬性進行設定。

在原本的 { toggle: false } 選項物件中,再加入一筆屬性 parent: <元素對象>來設定看看。

加入後直接在瀏覽器的開發者工具以 collapseList[0] 查看,展開物件可以看到指定的可折疊物件父項對象元素,也正確定指給對象元素 id="accordionExample"

接著操作手風琴 (Accordion) 元件,此時就與直接以 HTML 結構產生的靜態相關功能一樣,在操作上也會只呈現出唯一的收閤區塊。

bootstrap.js collapse 物件啟用後,優化 HTML 靜態結構移除用不到的標籤

aria-expanded="true" 或是 aria-expanded="false"aria-controls="collapseXxx"aria-labelledby="headingXxx" 這些指定為無障礙的標籤,除非頁面上真的是要有無障礙的規劃,不然可以省略。

手風琴 (Accordion) 元件指定的 ID 對象為 #accordionExample 元素,在所有使用 .collapse 成為 bootstrap.js 的 collapse 物件讓 JavaScript 可操作的對象後,可移除的是 data-bs-parent="#accordionExample" 標籤。

也因為由 bootstrap.js 的 collapse 物件選項設定,當由控制收閤區塊按鈕上的 data-bs-target="#collapseXxx" 操作觸發指定收閤的動作時,由於指定成收閤元素上的 .collapse
也就是 bootstrap.js 的 collapse 物件,都有由選項 parent: document.getElementById('accordionExample'), 的設定,讓操作時也就會去歷遍整 #accordionExample 下的 .collapse ,是否為 data-bs-target="" 內的指定元素,比對處理收/閉閤動作,而其他不是指定對象會直接閉閤動作。

接著,就可直接在瀏覽器開發者工具中,直接輸入 collapseList[0].toggle()collapseList[1].toggle()collapseList[2].toggle() 讓 JavaScript 直接於指定的 bootstrap.js 的 collapse 物件元素對象,進行操作也和原本 HTML 靜態功能範例一樣,會有唯一區塊的收閤動作。


靜態方法 getInstance 與 getOrCreateInstance,指定 DOM 元素取 collapse 物件與

new bootstrap.Collapse() 與 getOrCreateInstance() 建構 collapse 物件的異同

bootstrap 的 API 方法都非同步執行,執行建構式不會立即產生結果

在先前的方式是以在 HTML 與收閤相關結構,使用 JavaScript 針對元素對象進行建構、設定、操作,所使用的方式是以 new bootstrap.Collapse(<elementName>) 建構式將相關方法與設定設定。
這樣的方式操作對象元素時,若還沒有透過 bootstrap 相關方法建構出 collapse 物件的話,要使用 collapse 物件 collapse 物件中的相關方法是無法進行使用。

new bootstrap.Collapse(<elementName>) 是比較合適初始化 collapse 物件的一個方式,透過初始化可明確指出選項設定,也正式以新建構出的 collapse 物件,在沒有帶入選項設定時都會有預設設定值在物件內。

以下例來說,在沒使用 new bootstrap.Collapse(<elementName>) 方式產生出一個 collapse 物件時,在收閤元素的部份預設是沒有加上 .show 樣式的關閉狀態。

透過指 ID 元素以 new bootstrap.Collapse(<elementName>) 產生出 collapse 物件會有預設設定,其中的 toggle 是開始狀態,會自動加上 .show 樣式將開啟指定 ID 元素。

指定 ID 元素在產生物件後,也因為非同步執行的關係,宣告變數在存下 collapse 物件,在建構產生 collapse 物件後立即執行方法是會沒作用的。

但如果在產生 collapse 物件後,直接於瀏覽器開發者工具輸入 newCollapseObj.hide()newCollapseObj.toggle()newCollapseObj.show() 操作 collapse 物件看看,可直接沒問題的操作也是因為建構產生 collapse 物件。

建構完成出物件後,先暫時用 setTimeout() 設定時間,又或是透過點按按鈕來操作物件,在完整建構出物件後的使用相關的方法來操作指定 ID 元素。

new bootstrap.Collapse() 與 getOrCreateInstance() 建構 collapse 物件時,在執行前後會有指向不同物件,但操作對象同一個的差別

getOrCreateInstance(<elementName>) 是取 HTML 靜態結構中的指定元素的一個方法,這個方法執行時如果沒有產生出 collapse 物件時,會回傳並自動產生出一筆新的 collapse 物件。

而這樣的方式也和 new bootstrap.Collapse(<elementName>) 很像,一樣也有非同步建構 collapse 物件直接使用的問題,都可以將建構出來的結果賦予在變數上給之後重復呼叫使用,同樣透過 setTimeout() 一秒來做效果切換,証明確任有操作到 collapse 物件讓指定 ID 元素受到改變。

getOrCreateInstance(<elementName>) 在使用時,最後執行於 new bootstrap.Collapse(<elementName>) 的後方,這樣可以確保操作的是同一筆 collapse 物件。

  • setTimeout -> newCollapseObj === catchCollapseObj 回應是 true,這是同一個 collapse 物件。

特別注意到 new bootstrap.Collapse(<elementName>) 的後方提到前方,此時就會產生出新的 collapse 物件,這會讓操作對象同一個,但確使用的是不同的建構方法。

  • setTimeout -> newCollapseObj === catchCollapseObj 回應是 false,這是不同的 collapse 物件。
  • setTimeout -> newCollapseObj._element.id === catchCollapseObj._element.id 回應是 true,所指定的操作對象 ID 是 #CollapseExample 也是同對象。

以上的 collapse 物件建構方式,使用上需特別注意 new bootstrap.Collapse(<elementName>)getOrCreateInstance(<elementName>) 前後順序,也可避免造成產生出不同的物件讓除錯的難度提升。

getInstance 取操作對象在於 collapse 物件建立,沒有建立回應 null 取不到對象

getInstance() 是於 v5.0.0-alpha1 追加的功能 (較舊),比較目前最新加入 getOrCreateInstance() 方法取用操作對象元素的 collapse 物件方式不同,在沒有建立 collapse 物件時取用,會回應出 null (空值) 沒有建立,所建立後的元素對象才可透過此方法取得。


collapse 物件與對象元素執行時的事件

Collapse 收閤事件概念

Bootstrap 的收閤 (Collapse) 功能 (文件:),會在事件對象元素執行時由 .collapse (隱藏內容)、 .collapsing (轉換的過程中)、 .collapse.show (顯示內容) 的過程中切換相關的樣式,過程中在對象元素在頁面的高度或是絕對與相關位置都會改變,這些要明確取得較確任的位置或是對象元素的高度時,就需要在事件完成前後進行執行,才不會因為收閤 (Collapse) 功能執行的過程中,取得處理中的內容,造錯不正確的使用。

相關後續內容以下例與程式碼做說明。

操作指定收閤元素切換按鈕,以 collapse 物件下的 .toggle() 方法,將指定元素做開關收閤的切換動作。

shown.bs.collapse 事件 (完成展開),collapse 物件產生於對象元素時,就先直接觸發

'shown.bs.collapse' 會於對象元素產生出 collapse 元素時就觸發,在 JavaScript 執行將目標元素 new bootstrap.Collapse(collapseElementID) 完成建構式時,會先執行預設的 { toggle: true} 設定,此時一開始載入頁面的收閤就會是展開的情形,這裡也就會直接觸發 'shown.bs.collapse' 事件。

'shown.bs.collapse' 事件的相關內容,需透過 .addEventListener() 內的函式,以函式中 event 的參數取得,可看到取得後展開所取得的 shown.bs.collapse 物件,在透過指定對象元素的綁定之後,在操作時如果有做 完成展開 的動作,此時就可重覆執行。

hidden.bs.collapse 事件 (完成關閉),在切換對象元素收閤關閉時觸發執行

指定對象元素的綁定 'hidden.bs.collapse' 事件,在操作收閤完成關閉時就會觸發,一樣也是透過 .addEventListener() 內的函式,以 e 的 event 事件做為參數,執行時才可取得 hidden.bs.collapse 物件。


其他資料

Bootstrap 发布十周年,Bootstrap 5都有什么新功能?