0%

用JavaScript自幹一個下拉多選單(MultiSelector)

前言

今天接到一個使用者需求,希望將下拉選單改成多選
其實隨便找個JQuery套件,應該馬上搞定…

不過由於專案實在是挺舊的,是個.NET 2.0 WebFrom專案
想了一會兒,反正也不是什麼困難的需求,剛好就拿來練練基本功吧..

既然要練習基本功,那麼就決定回歸原始!只用最基本的CSS + JavaScript來做這個功能..

(本網頁Demo不支援IE瀏覽器..)

思考過程

為了配合一下WebForm的控制項,這樣在PostBack取值的時候只要把 DropDownList 改成 ListBox 並設成 SelectionMode="MultiSimple"應該就搞定了

觀察一下就知道, ListBox 在網頁上其實會產生像這樣的 Element:

1
2
3
4
5
<select class="multi-selector" multiple>
<option value="Item1">Item1</option>
<option value="Item2">Item2</option>
<option value="Item3">Item3</option>
</select>

Demo:

嗯…這東西實在是很醜,且完全不是我們想要的,
那麼只好自己寫一個UI,將選項同步,然後將原本的UI藏起來讓使用者看不到,這樣就可以了吧!

動工

Step1. 首先先定義一下我們的結構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="dropdown">
<div class="item text">
<label></label>
</div>
<div class="item">
<input type="checkbox" value="Item1"/>
<span>Item1</span>
</div>
<div class="item">
<input type="checkbox" value="Item2"/>
<span>Item2</span>
</div>
<div class="item">
<input type="checkbox" value="Item3"/>
<span>Item3</span>
</div>
</div>

Step2. CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* 讓元素不要換行 */
.dropdown {
display:inline-block;
height: 30px;
z-index: 2;
}

/* 定義 Item 的寬高,margin-top:-1px 讓線重疊,調整間距 */
.dropdown .item {
width: 180px;
height: 30px;
border: 1px solid #ccc;
margin: -1px 0px 0px;
padding: 0px 10px;
box-sizing: border-box;
box-shadow: 0 0 3px #ccc;
background: #fff;
}

/* 讓第二個之後的Item隱藏 */
.dropdown .item + .item{
display:none;
}

/* 滑鼠移到任何Item時,顯示 */
.dropdown:hover .item {
display: block;
}

/* 讓文字垂直置中 */
.dropdown .text label,
.dropdown .item span,
.dropdown .item input[type="checkbox"] {
line-height: 30px;
}

/* 讓lebal為空的時候顯示文字 */
.dropdown .text label:empty:after {
content: '請選擇項目';
color: #ccc;
}

跟原本的元素放在一起比較看看:

嗯…看起來長相差不多了

Step3. JavaScript產生結構

接下來,就用JavaScript來讀取原本的element,並產生剛剛定義好的新的結構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function initMultiElement() {
//產生div.dropdown 和 label區塊
var multiElement = document.createElement('div');
multiElement.setAttribute('class', 'dropdown');
var html = `<div class="item text">
<label></label>
</div>`;

//forEach 原本的 ListBox (剛剛有先設class="multi-selector"), 取出option value 在寫成新的結構
document.querySelectorAll('.multi-selector option').forEach(function(optionItem){
html += `<div class="item">
<input type="checkbox" value="${optionItem.value}"/>
<span>${optionItem.text}</span>
</div>`
})
multiElement.innerHTML = html;
document.querySelector('.multi-selector').parentElement.appendChild(multiElement);
setMultiElementEvent(); //設定點擊事件
}

點擊checkbox時,要連動原本的ListBox選項

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function setMultiElementEvent()
{
// foreach checkbox 設定 click 事件
document.querySelectorAll('.item input[type="checkbox"]').forEach(function(checkItem){
checkItem.addEventListener("click", function(e){
//紀錄有被選到的選項value
let resultText = '';
let checkedItems = document.querySelectorAll('.item input:checked[type="checkbox"]')
checkedItems.forEach(function(selectItem){
if(resultText !== '')
resultText += ','
resultText += selectItem.value
})

//把被勾選的value寫入Label
document.querySelector('.dropdown .text label').innerText = resultText
//找原本的ListBox value相等的元素,同時做勾選或取消
document.querySelector('.multi-selector option[value="'+e.srcElement.value+'"]').selected = e.srcElement.checked
});
})
}

最後在window.onload時呼叫initMultiElement()

1
2
3
window.onload = function() {
initMultiElement();
}

搞定

結果

現在我們定義好的HTML結構已經全部用JavaScript來產生,那馬上來看看結果:

成功,現在選取的元素時會將原本的 ListBox 也一起選取起來了,
那最後只要把原本的 ListBox 給偷偷藏起來不要讓使用者發現就行囉!

1
2
3
4
5
6
/* 直接把寬高設為0,透明度也設為0 */
.multi-selector {
width: 0px;
height: 0px;
opacity: 0;
}

心得

在剝奪了各種框架套件之後,要寫這些功能確實是麻煩了許多,
不過這種練習還是能學到蠻多東西的,算是重新練習基本功吧!

↓↓↓ 如果喜歡我的文章,可以幫我按個Like! ↓↓↓
>> 或者,請我喝杯咖啡,這樣我會更有動力唷! <<<
街口支付

街口支付

街口帳號: 901061546

歡迎關注我的其它發布渠道