FAQ區塊常見UI是標題旁邊有+或-的icon,用來切換顯示下方的內容。
2種模式做切換 => toggle方法
預計延伸的筆記大綱:
- 一組QA來解析程式碼 (本篇)
- 兩組以上的QA
- plain JS 寫法
- React 寫法
- display none 和 block切換 => 效能問題?
- 細節優化
- 注意事項
1. 一組QA來解析程式碼 codepen
//html
<li class="qa-item">
<div class="question-wrapper">
<p class="question">預設是彩色tulip且不顯示內容</p>
<div class="modeToggle-icon-wrapper">
<img class="modeToggle-icon" data-mode="plus"
src="https://im..." alt="icon-plus">
</div>
</div>
<div class="answer hide">Lorem ipsum ....</div>
</li>
//js
const modeToggleIcon = document.querySelector('.modeToggle-icon')
const answer= document.querySelector('.answer')
const srcs = {
"plus":"https://ima...",
"minus": "https://ima..."
}
function showOrHideContent() {
answer.classList.toggle('hide');
answer.classList.toggle('show');
}
modeToggleIcon.addEventListener('click', function() {
let mode = this.dataset.mode
mode = mode === "plus" ? "minus" : "plus"
this.src = srcs[mode]
this.dataset.mode = mode
document.body.classList.toggle("plus", mode==="plus")
//顯示或隱藏內容
showOrHideContent()
})
document.body.classList.toggle("plus", modeToggleIcon.dataset.mode==="plus")
//CSS
.question-wrapper {
width: 100%;
height: 38px;
margin-bottom: 24px;
display: flex;
border: 1px solid blue;
justify-content: space-between;
align-items: center;
}
.question {
font-weight: 600;
font-size: 1rem;
color: var(--dark-purple);
}
.modeToggle-icon-wrapper {
margin-left: 24px;
height: 30px;
min-width: 30px;
max-width: 30px;
}
.modeToggle-icon-wrapper img {
width: 100%;
height: 100%;
}
.modeToggle-icon-wrapper img:hover {
border: 1px solid red;
cursor: pointer;
}
.minus-wrapper img {
width: 100%;
height: 100%;
}
.minus-wrapper img:hover {
border: 1px solid red;
cursor: pointer;
}
.answer {
border: 1px solid blue;
font-weight: 400;
color: var(--grayish-purple);
font-size: 0.875rem;
line-height: 150%;
}
.answer.hide {
display: none;
}
.answer.show {
display: block;
}
功能: 點擊切換icon來顯示或隱藏內容。
1. 選取元素和定義變數
const modeToggleIcon = document.querySelector('.modeToggle-icon')
const answer = document.querySelector('.answer')
const srcs = {
"plus": "https://ima...",
"minus": "https://ima..."
}
- 選取元素modeToggleIcon: 選取class name 為 .modeToggle-icon 的icon元素
<img>
,作為切換顯示模式。 - 選取元素answer: 選取class name 為 .answer 的元素,要被顯示或隱藏的内容。
srcs: 一個物件,包含2個key-value pair,分別對應不同icon模式的圖片來源。
2. 顯示或隱藏内容的函式
function showOrHideContent() {
answer.classList.toggle('hide');
answer.classList.toggle('show');
}
showOrHideContent
函式透過在 answer 元素上切換class name .hide
和.show
作為切換顯示與否的狀態。
MDN | DOMTokenList: toggle() method
節點的toggle()方法,從清單中刪除現有token並回傳false。如果token不存在,則會新增該token並且函式回傳true。
toggle(token)
toggle(token, force)
token-表示您要切換的token的字串
force-(選)若有包含,則將toggle變為單向操作。
若設定為false,則token只會被刪除,不會新增。
如果設定為true,則token只會被添加,不會刪除。
傳回值
布林值true或false,表示token被呼叫後是否在列表中。
3. 點擊事件監聽器
modeToggleIcon.addEventListener('click', function() {
1 let mode = this.dataset.mode
2 mode = mode === "plus" ? "minus" : "plus"
3 this.src = srcs[mode]
4 this.dataset.mode = mode
5 document.body.classList.toggle("plus", mode === "plus")
// 顯示或隱藏内容
6 showOrHideContent()
})
註冊點擊事件監聽器, .modeToggle-icon 元素被點擊時觸發。
1 獲取當前icon的模式(plus 或 minus),並切換成另一個模式。
2, 3 根據當前模式切換icon的src屬性,即對應模式的icon圖檔。
this.src = srcs[mode]
- this 在此是被點擊的
<img .modeToggle-icon >
元素。 - srcs 物件,包含了兩個 icon的圖檔
- mode 變數,表示當前的模式,可以是 "plus" 或 "minus"。
根據當前的 mode 值,透过 srcs[mode] 來得到相應的圖檔,並將其賦值给this.src
,更新icon。
<img class="modeToggle-icon" data-mode="plus"
src="https://im..." alt="icon-plus">
4 更新 dataset.mode 屬性以反應當前模式。
this.dataset.mode = mode;
dataset
屬性是 DOM 元素的屬性,用來訪問該元素上的自定義數據屬性。
mode 變數,它的值是當前的模式,可以是 "plus" 或 "minus"。
透過將 mode 賦值给 this.dataset.mode,更新了 元素上的 data-mode
屬性的值。
這個屬性通常用來儲存元素的自定義狀態或訊息,這裡用來記錄當前顯示的icon模式,以便後續的狀態切換邏輯可根據此屬性值,進行判斷和執行相應的操作。
5 根據當前模式,將 body 元素的class name 切換成 plus 或移除 plus。
6 呼叫 showOrHideContent 函式來切換顯示或隱藏的内容。
透過監聽icon的點擊事件,實現了點擊切換 icon 來顯示或隱藏内容。利用classList.toggle
方法和 dataset
屬性來切換元素的狀態和屬性,同時根據當前狀態更新icon的顯示。