瀏覽器自帶的原生下拉框不太美觀,而且各個(gè)瀏覽器表現(xiàn)也不一致,UI一般給的下拉框也是和原生的下拉框差別比較大的,這就需要自己寫一個(gè)基本功能的下拉菜單/下拉選擇框了。最近,把項(xiàng)目中用到的下拉框組件重新封裝了一下,以構(gòu)造函數(shù)的方式進(jìn)行封裝,主要方法和事件定義在原型上,下面是主要的實(shí)現(xiàn)代碼并添加了比較詳細(xì)的注釋,分享出來(lái)供大家參考。代碼用了ES6部分寫法如需兼容低版本瀏覽器請(qǐng)把相關(guān)代碼轉(zhuǎn)成es5寫法,或者直接bable轉(zhuǎn)下。
先放個(gè)預(yù)覽圖吧,后面有最終的動(dòng)態(tài)效果圖:(樣式和交互參考了阿里和Iview UI庫(kù))
下面是主要的HTML代碼(包含部分js調(diào)用代碼):
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Diy Select</title> <link rel="stylesheet" href="index.css" rel="external nofollow" > </head> <body> <div id="main" class="main"></div> <script src="index.js"></script> <script> document.addEventListener("DOMContentLoaded",function(){ const select1 = new $Selector({ eleSelector:"#main", options:[ {name:"選項(xiàng)1",value:"0"}, {name:"選項(xiàng)2",value:"1"}, {name:"選項(xiàng)3",value:"2"} ], defaultText:"選項(xiàng)2" }); }) </script> </body> </html>
頁(yè)面中定義了id為main的div,即為選擇框所要添加到的元素。傳入?yún)?shù)即可。
接著就是樣式CSS部分了,沒啥說(shuō)的了,手動(dòng)滑稽:
* { padding: 0; margin: 0; box-sizing: border-box; } .main { padding: 40px; } .my-select { display: inline-block; width: auto; min-width: 80px; box-sizing: border-box; vertical-align: middle; color: #515a6e; font-size: 14px; line-height: normal; position: relative; } .select-selection { display: block; box-sizing: border-box; outline: 0; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; cursor: pointer; position: relative; background-color: #fff; border-radius: 4px; border: 1px solid #dcdee2; transition: all .2s ease-in-out; } .select-selection:hover, .select-selection.select-focus { border-color: #57a3f3; box-shadow: 0 0 0 2px rgba(45, 140, 240, .2); } .select-selected-value { display: block; height: 28px; line-height: 28px; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-left: 8px; padding-right: 24px; } .icon-select-arrow { position: absolute; top: 50%; right: 8px; line-height: 1; margin-top: -7px; font-size: 14px; color: #808695; transition: all .2s ease-in-out; display: inline-block; font-style: normal; font-weight: 400; font-variant: normal; text-transform: none; text-rendering: auto; line-height: 1; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; vertical-align: middle; } .icon-select-arrow::before { content: ""; display: block; width: 6px; height: 6px; background-color: transparent; border-left: 1.5px solid #808695; border-bottom: 1.5px solid #808695; transform: rotate(-45deg); } .select-dropdown { width: auto; min-width: 80px; max-height: 200px; overflow: auto; margin: 5px 0; padding: 5px 0; background-color: #fff; box-sizing: border-box; border-radius: 4px; box-shadow: 0 1px 6px rgba(0, 0, 0, .2); position: absolute; z-index: 2; transform-origin: center top 0px; transition: all 0.3s; will-change: top, left; top: 30px; left: 0; transform: scale(1, 0); opacity: 0; } .select-item { line-height: normal; padding: 7px 16px; clear: both; color: #515a6e; font-size: 12px !important; white-space: nowrap; list-style: none; cursor: pointer; transition: background .2s ease-in-out; } .select-item.select-item-selected, .select-item:hover { color: #2d8cf0; background-color: #f3f3f3; }
樣式部分就不做什么解釋了,下面放入壓軸的JS,同樣也無(wú)需過(guò)多解釋,注釋寫的很詳細(xì)了,上代碼:
/* jshint esversion: 6 */ (function (window, document) { let Selector = function (option) { //執(zhí)行初始化方法, this._init(option); }; Selector.prototype = { //初始化傳入?yún)?shù)并定義初始化的相關(guān)變量 _init({ eleSelector = "", //傳入的選擇器 id,class,tag等,用于將選擇框渲染到此選擇器所在的元素 options = [{ name: "請(qǐng)選擇", value: "0", }], //傳入的下拉框?qū)ο?,name為選擇的文字,value為值 defaultText = "請(qǐng)選擇" //提供的默認(rèn)選擇的值 }) { //將傳入的數(shù)據(jù)綁定到this上 this.parentEle = document.querySelector(eleSelector) || document.body; //要邦定的dom this.options = options; //選擇值數(shù)組對(duì)象 this.defaultText = defaultText; //默認(rèn)值 this.dropboxShow = false; //定義存儲(chǔ)下拉框的顯示隱藏狀態(tài) this.defaultValue = ""; //定義村赤默認(rèn)選中的值 this._creatElement(); //初始化后執(zhí)行創(chuàng)建元素方法 }, //創(chuàng)建下拉選擇框dom _creatElement() { //選擇框最外層的包裹元素 let wrapEle = document.createElement("div"); wrapEle.className = "my-select"; //根據(jù)傳入的值獲取選擇框默認(rèn)的值和內(nèi)容 this.options.forEach(item => { if (item.name === "this.defaultText") { this.defaultValue = item.value; } }); let selectWarpBox = document.createElement("div"); //選擇框包裹元素 selectWarpBox.className = "select-selection"; let inputHideBox = document.createElement("input"); //隱藏保存選擇值得元素 inputHideBox.type = "hidden"; inputHideBox.value = this.defaultValue; let selectShowBox = document.createElement("div"); //選擇框默認(rèn)展示框 let selectNameBox = document.createElement("span"); //選擇框展現(xiàn)的值ele selectNameBox.className = "select-selected-value"; selectNameBox.id = "select-option"; selectNameBox.innerText = this.defaultText; //將傳入的默認(rèn)值賦值 let selectIcon = document.createElement("i"); //圖標(biāo)ele selectIcon.className = "arrow-down icon-select-arrow"; //將span和角標(biāo)添加到外層div selectShowBox.appendChild(selectNameBox); selectShowBox.appendChild(selectIcon); selectWarpBox.appendChild(inputHideBox); selectWarpBox.appendChild(selectShowBox); //下拉框 let dropbox = document.createElement("div"), ulbox = document.createElement("ul"); dropbox.id = "select-drop"; dropbox.className = "select-dropdown"; ulbox.className = "select-dropdown-list"; //遍歷傳入的選項(xiàng)數(shù)組對(duì)象,生成下拉菜單的li元素并賦值 this.options.forEach((item) => { let itemLi = document.createElement("li"); if (this.defaultText === item.name) { itemLi.className = "select-item select-item-selected"; } else { itemLi.className = "select-item"; } itemLi.setAttribute("data-value", item.value); itemLi.innerText = item.name; ulbox.appendChild(itemLi); }); //將下拉框ul推入到包裹元素 dropbox.appendChild(ulbox); wrapEle.appendChild(selectWarpBox); wrapEle.appendChild(dropbox); this.parentEle.appendChild(wrapEle); //將生成的下拉框添加到所選元素中 //把需要操作的dom掛載到當(dāng)前實(shí)例 //this.wrapEle = wrapEle; //最外層包裹元素 this.eleSelect = selectWarpBox; //選擇框 this.eleDrop = dropbox; //下拉框 this.eleSpan = selectNameBox; //顯示文字的span節(jié)點(diǎn) //綁定事件處理函數(shù) this._bind(this.parentEle); }, //點(diǎn)擊下拉框事件處理函數(shù) _selectHandleClick() { if (this.dropboxShow) { this._selectDropup(); } else { this._selectDropdown(); } }, //收起下拉選項(xiàng) _selectDropup() { this.eleDrop.style.transform = "scale(1,0)"; this.eleDrop.style.opacity = "0"; this.eleSelect.className = "select-selection"; this.dropboxShow = false; }, //展示下拉選項(xiàng) _selectDropdown() { this.eleDrop.style.transform = "scale(1,1)"; this.eleDrop.style.opacity = "1"; this.eleSelect.className = "select-selection select-focus"; this.dropboxShow = true; }, //點(diǎn)擊下拉選項(xiàng)進(jìn)行賦值 _dropItemClick(ele) { this.defaultValue = ele.getAttribute("data-value"); //document.querySelector("#select-value").value = ele.getAttribute("data-value"); this.eleSpan.innerText = ele.innerText; ele.className = "select-item select-item-selected"; //對(duì)點(diǎn)擊選中的其他所有兄弟元素修改class去除選中樣式 this._siblingsDo(ele, function (ele) { if (ele) { ele.className = "select-item"; } }); this._selectDropup(); }, //node遍歷是否是子元素包裹元素 _getTargetNode(ele, target) { //ele是內(nèi)部元素,target是你想找到的包裹元素 if (!ele || ele === document) return false; return ele === target ? true : this._getTargetNode(ele.parentNode, target); }, //兄弟元素遍歷處理函數(shù) _siblingsDo(ele, fn) { (function (ele) { fn(ele); if (ele && ele.previousSibling) { arguments.callee(ele.previousSibling); } })(ele.previousSibling); (function (ele) { fn(ele); if (ele && ele.nextSibling) { arguments.callee(ele.nextSibling); } })(ele.nextSibling); }, //綁定下拉框事件處理函數(shù) _bind(parentEle) { let _this = this; //事件委托到最外層包裹元素進(jìn)行綁定處理 parentEle.addEventListener("click", function (e) { const ele = e.target; //遍歷當(dāng)前點(diǎn)擊的元素,如果是選中框內(nèi)的元素執(zhí)行 if (_this._getTargetNode(ele, _this.eleSelect)) { if (_this.dropboxShow) { _this._selectDropup(); } else { _this._selectDropdown(); } } else if (ele.className === "select-item") { //如果是點(diǎn)擊的下拉框的選項(xiàng)執(zhí)行 _this._dropItemClick(ele); } else { //點(diǎn)擊其他地方隱藏下拉框 _this._selectDropup(); } }); } }; //將構(gòu)造函數(shù)掛載到全局window window.$Selector = Selector; })(window, document);
到此,一個(gè)自定義下拉菜單就出爐了,下面是動(dòng)態(tài)效果:
至此,從css自定義的表單元素到下拉框元素都已經(jīng)自定義完畢,使用bootstrap的同學(xué)把這些加進(jìn)去就能基本保持各瀏覽器效果一致性和美觀性了,就到這吧先。
推薦:
感興趣的朋友可以關(guān)注小編的微信公眾號(hào)【碼農(nóng)那點(diǎn)事兒】,更多網(wǎng)頁(yè)制作特效源碼及學(xué)習(xí)干貨哦!??!
總結(jié)
以上所述是小編給大家介紹的原生js實(shí)現(xiàn)一個(gè)自定義下拉單選選擇框功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com