這兩天在寫一個chrome插件,需要在popup頁使用下拉多選框咧擂。用select看起來非常原始,多選還要按住ctrl鍵或者command鍵。
html代碼如下:
<html>
<head>
<title>用select實(shí)現(xiàn)下拉多選框</title>
</head>
<body>
<select class="demo" multiple="multiple">
<option value="cp">C++</option>
<option value="cs">C#</option>
<option value="oc">Object C</option>
<option value="c">C</option>
</select>
</body>
</html>
效果如下振惰,真是。垄懂。骑晶。
看來必須要有css的加持,否則真是不堪入目草慧。但是買的《CSS揭秘》一頁還沒看透罢,遠(yuǎn)水解不了近渴。先在網(wǎng)上找找吧冠蒋。
在free.js上找到了一個好方法羽圃。鑒于自己對html/css和jQuery只是一知半截,認(rèn)真看了一遍free.js提供的代碼抖剿,也算是學(xué)習(xí)了css和jQuery的實(shí)戰(zhàn)用法朽寞。
先看下效果,一樣的select斩郎,不一樣的味道脑融。css和jquery真是能化腐朽為神奇啊。
html代碼:
<html>
<head>
<link href="fSelect.css" rel="stylesheet" type="text/css">
<title>用select+css實(shí)現(xiàn)下拉多選框</title>
</head>
<body>
<select class="demo" multiple="multiple">
<optgroup label="Languages">
<option value="cp">C++</option>
<option value="cs">C#</option>
<option value="oc">Object C</option>
<option value="c">C</option>
</optgroup>
<optgroup label="Scripts">
<option value="js">JavaScript</option>
<option value="php">PHP</option>
<option value="asp">ASP</option>
<option value="jsp">JSP</option>
</optgroup>
</select>
<script src="jquery-1.11.3.min.js"></script>
<script src="fSelect.js"></script>
<script>
$(function() {
$('.demo').fSelect();
});
</script>
</body>
</html>
這里除了用到了select的multiple屬性缩宜,還用到了optgroup屬性肘迎。這個屬性能將option分組。
除此之外锻煌,我們在html中還加了新的調(diào)料:css和jquery妓布。
jquery和fSelect.js改變了html的樣子。腳本執(zhí)行后的html是這個樣子的:
那么宋梧,我們怎么施了魔法匣沼,把html變了樣呢?
先從入口說起吧捂龄。在</body>前的<script>調(diào)用了一個jquery函數(shù):
$(function() {
$('.demo').fSelect();
});
這里用了兩個簡寫释涛,一個是$(...)是jQuery(...)的簡寫。另一個簡寫是$(function() {...});倦沧,它的全寫形式是:
$(document).ready(function(){...})
ready函數(shù)能保證在頁面就緒后再調(diào)用我們寫的匿名函數(shù)唇撬。其實(shí)這有點(diǎn)多此一舉,因?yàn)檫@個函數(shù)已經(jīng)是緊挨著</body>之前了展融,函數(shù)的位置可以保證腳本運(yùn)行前HTML已經(jīng)加載到DOM里面窖认。
剝開這個函數(shù),可以看到核心代碼是$('.demo').fSelect()。這又是一個jquery的函數(shù)耀态,函數(shù)參數(shù)'.demo'是個jQuery選擇器轮傍,類似css選擇器,它匹配class屬性為demo的元素首装,對應(yīng)HTML创夜,則是select。然后對這個下拉框執(zhí)行fSelect方法仙逻。fSelect不是jquery定義的方法驰吓,而是fSelect.js注冊給jquery的。
我們再看看fSelect.js:
主函數(shù)體是(function($) {...})(jQuery)系奉。這又是一種慣用法檬贰,定義一個匿名函數(shù)(函數(shù)參數(shù)是$,其實(shí)就是jQuery)缺亮,然后馬上調(diào)用這個匿名函數(shù)翁涤。這個函數(shù)的作用是把一些自定義的函數(shù)和屬性注入到j(luò)query或者DOM里面。
第三行$.fn.fSelect = function(options) {...}就是給$.fn增加一個方法fSelect萌踱,也就是在html調(diào)用的函數(shù)葵礼。
我們再仔細(xì)看看fSelect的實(shí)現(xiàn):
第21行定義了fSelect的構(gòu)造函數(shù)。接著在30行定義了它的prototype并鸵,其中定義了create等接口鸳粉。最后在105行,為jquery選擇器匹配上的每個元素都添加各自的fSelect對象园担。
接下來届谈,我們一步一步看fSelect的各個函數(shù)。先從構(gòu)造函數(shù)看起:
構(gòu)造函數(shù)先用this指針把參數(shù)select和settings保存起來弯汰。js的this在不同的上下文有不同的含義(主要有三種含義)艰山,在構(gòu)造函數(shù)里面的this是指向即將創(chuàng)造出來的對象。第22行為新對象增加了一個屬性$select蝙泼,屬性名有點(diǎn)奇怪程剥,這是jquery的習(xí)慣用法劝枣,為保存jquery對象的變量都以$開頭汤踏。
讓我們再看下原型方法create。順便說下舔腾,原型在js有非常大的作用溪胶,通過原型可以實(shí)現(xiàn)繼承,動態(tài)增刪屬性稳诚,改變對象行為哗脖。
回到create:
- 32行-33行,是把select包到一個新的div里面。因?yàn)閔tml定義的select帶有multiple屬性才避,這個div屬于兩個class(fs-wrap和multiple)橱夭。
- 34行:在select之前插入兩個div(類分別為fs-label-wrap和fs-lable)和一個span(類為fs-arrow)。
- 35行:再在select之前插入兩個div(類分別為fs-dropdown hidden和fs-options)桑逝。這兩個div比34行加的兩個div更靠近select*棘劣。
- 36行:select加入到類hidden,把select整個元素都設(shè)置為不可見楞遏。
- 37行:又定義一個jquery變量茬暇,$wrap,保存當(dāng)前select 的第一個類為fs-wrap**的祖先元素寡喝。
- 38行:調(diào)用另一個原型方法reload糙俗。
reload: - 43-47行:在類fs-dropdown(一個div)的開始標(biāo)簽之后插入一個用于搜索的div(類為fs-search)。
- 48行:根據(jù)select的options预鬓,生成用div實(shí)現(xiàn)的新choices巧骚。
- 49行:把新生成的choices插入到fs-options類的div中。
- 50行:調(diào)用reloadDropdownLabel格二,將用戶選中的options更新到fs-label中网缝,并觸發(fā)select的change事件。
讓我們再看看option的點(diǎn)擊事件響應(yīng):
- 159-174行:把選中的options保存到selected數(shù)組中蟋定。
- 176行:根據(jù)selected粉臊,更新select的選中options。
- 177行:調(diào)用reloadDropdownLabel驶兜,將用戶選中的options更新到fs-label中扼仲,并觸發(fā)select的change事件。
從上面代碼分析可以看出抄淑,select一開始就隱藏起來了屠凶,我們看到的和操作的都是腳本生成的div。然后div的變化會聯(lián)動到select上肆资,并觸發(fā)它的change事件矗愧。