在寫示例的時候,用到了下拉框,可是原生的下拉框是在是有點難看,而後模仿着寫了點,一個是直接在寫好的Dom上進行美化,一個是用js生成,而後定義類名及相應的事件來處理
<div class="root"> <div id="selectedItem"> <div id="promptText"><span id="spanText">請選擇你喜歡的文字</span><img src="../images/arrowup.png" id="arrows" /></div> <ul class="choiceDescription"> <li class="item">萬水千山,陪你一塊兒看</li> <li class="item">萬水千山,陪你一塊兒看1</li> <li class="item">萬水千山,陪你一塊兒看2</li> <li class="item">萬水千山,陪你一塊兒看3</li> <li class="item">萬水千山,陪你一塊兒看4</li> </ul> </div> </div>
ul{ margin: 0; padding: 0; list-style: none; } /* 下拉框包含層 */ #selectedItem{ width: 240px; cursor: pointer; } /* 已選中的選項 */ #promptText{ position: relative; padding-left: 10px; width: 230px; height: 30px; line-height: 30px; border: 1px solid #d3d3d3; border-radius: 4px; background: #fff; color: #999; font-size: 14px; } /* 圖標 */ #arrows{ position: absolute; top: 0; right: 0; width: 30px; height: 30px; vertical-align: middle; } #arrows:focus{ outline: none; } /* 下拉可選項包含層 */ .choiceDescription{ position: absolute; display: none; /*overflow: hidden;*/ margin-top: 2px; width: 240px; border: 1px solid #ccc; border-radius: 4px; box-shadow: 0 1px 6px rgba(0, 0, 0, .1); background: #fff; } .show{ display: block; } /* 下拉可選項 */ .item{ height: 30px; line-height: 30px; padding-left: 10px; font-size: 15px; color: #666; } .item:hover{ color: #fff; background: rgba(49, 255, 195, 0.67); }
(function() { let choiceDescription = document.getElementsByClassName('choiceDescription')[0]; let arrows = document.getElementById('arrows'); /* 用於判斷是不是下拉 */ let isDown = false; let selectedItem = document.getElementById('selectedItem'); /* 對點擊下拉進行監聽 */ selectedItem.addEventListener('click', function() { isDown = !isDown; if(isDown) { /* 若是是下拉狀態,則顯示下拉的選項,並把圖標顯示爲向下的圖標 */ choiceDescription.className += ' show'; arrows.src = '../images/arrowdown.png'; } else { choiceDescription.className = 'choiceDescription'; arrows.src = '../images/arrowup.png'; } }); choiceDescription.addEventListener('click', function(e) { let promptText = document.getElementById('spanText'); let selectElement = e.target; /* 判斷是否點擊的是li標籤,防止點擊了li標籤之外的空白位置 */ while(selectElement.tagName !== 'LI') { /* 若是點中的是當前容器層 */ if(selectElement == choiceDescription) { selectElement = null; break; } /* 若果不是,則再找父級容器 */ selectElement = selectElement.parentNode; } /* innerText、innerHTML、value * innerText 是指html標籤裏的文字信息,單純的文本,不會有html標籤,存在兼容性 * innerHTML 是指包含在html標籤裏的全部子元素,包括空格、html標籤 * value 表單裏的元素屬性值 * */ if(selectElement) { promptText.innerHTML = e.target.innerHTML; } }); })()
<div id="select" class="select"></div> <script src="autoGenerateSelect.js"></script> <script> (function() { /* 當 onload 事件觸發時,頁面上全部的DOM,樣式表,腳本,圖片,flash都已經加載完成了 * 當 DOMContentLoaded 事件觸發時,僅當DOM加載完成,不包括樣式表,圖片,flash */ document.addEventListener('DOMContentLoaded',function(){ new $Selector({ elementSelector:'#select', options:[ {name:'選項1',value:'0'}, {name:'選項2',value:'1'}, {name:'選項3',value:'2'} ], defaultText:'選項2' }); }) })() </script>
*css文件css
html, body, ul{ margin: 0; padding: 0; } ul{ list-style: none; } #select{ padding: 30px 40px 0; } /* 下拉框 */ .dropDown{ position: relative; display: inline-block; min-width: 120px; box-sizing: border-box; color: #515a6e; font-size: 14px; } /* 已選中的值包含層 */ .selectedOption{ position: relative; box-sizing: border-box; outline: none; user-select: none; cursor: pointer; background: #fff; border-radius: 4px; border: 1px solid #dcdee2; transition: all .2s ease-in-out; } .selectedValue{ display: block; overflow: hidden; height: 28px; line-height: 28px; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; padding-left: 8px; padding-right: 24px; } /* 圖標 */ .arrowDown{ position: absolute; display: inline-block; top: 50%; right: 8px; margin-top: -7px; font-size: 14px; color: #808695; transition: all .2s ease-in-out; /* 字體抗鋸齒渲染 */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .arrowDown:before{ content: ""; display: block; width: 6px; height: 6px; background-color: transparent; border-left: 2px solid #808695; border-bottom: 2px solid #808695; transform: rotate(-45deg); } /* 全部選項的包含層 */ .optionsContainer{ position: absolute; top: 30px; left: 0; min-width: 120px; max-height: 200px; margin: 5px 0; padding: 5px 0; background: #fff; box-sizing: border-box; border-radius: 4px; box-shadow: 0 1px 6px rgba(0, 0, 0, .2); z-index: 2; transform-origin: center top 0px; transition: all 0.3s; will-change: top, left; transform: scale(1, 0); opacity: 0; } /* 每一個選項 */ .optionsItem{ line-height: normal; padding: 7px 16px; color: #515a6e; font-size: 12px; white-space: nowrap; cursor: pointer; transition: background .2s ease-in-out; } .itemSelected, .optionsItem:hover{ color: #2d8cf0; background-color: #f3f3f3; }
/* 私有方法:初始化下拉框 */ _initSelector({ /* 傳入id,class,tag,用於掛載下拉框 */ elementSelector = '', /* 傳入的下拉框選項 */ options = [{ name: '請選擇你喜歡的顏色', value: '0' }], defaultText = '請選擇你喜歡的顏色' }) { /* 找到要掛載的Dom節點 */ this.parentElement = document.querySelector(elementSelector) || document.body; this.options = options; this.defaultText = defaultText; /* 下拉框的顯示與隱藏狀態 */ this.downStatus = false; /* 下拉框默認選中的值 */ this.defaultValue = ''; this._createElement(); },
/* 建立Dom節點 */ _createElement() { /* 建立下拉框最外層 */ let dropDown = document.createElement('div'); dropDown.className = 'dropDown'; /* 已選中的選項值 */ let selectedOption = document.createElement('div'); selectedOption.className = 'selectedOption'; /* 選中的值 */ let selectedValue = document.createElement('span'); selectedValue.className = 'selectedValue'; /* 先賦值爲默認值 */ selectedValue.innerText = this.defaultText; /* 向下的圖標 */ let downIcon = document.createElement('i'); downIcon.className = 'arrowDown'; /* 將已選中的值的層添加到Dom節點中 */ selectedOption.appendChild(selectedValue); selectedOption.appendChild(downIcon); /* 建立選項的外層容器 */ let optionsContainer = document.createElement('div'); optionsContainer.className = 'optionsContainer'; /* 用ul來包含選項層 */ let ulOptionsList = document.createElement('ul'); ulOptionsList.className = 'ulOptionsList'; /* 循環建立每一個選項 */ this.options.forEach((item) => { let optionsItem = document.createElement('li'); /* 是不是選中狀態 */ if(item.name == this.defaultText) { optionsItem.className = 'optionsItem itemSelected'; } else { optionsItem.className = 'optionsItem'; } optionsItem.innerText = item.name; ulOptionsList.appendChild(optionsItem); }); /* 添加到每一個對應的元素裏面 */ optionsContainer.appendChild(ulOptionsList); dropDown.appendChild(selectedOption); dropDown.appendChild(optionsContainer); this.parentElement.appendChild(dropDown); /* 設置Dom元素,掛載、綁定事件 */ /* 已選中的選項的包含層 */ this.selectedOption = selectedOption; /* 選中的值 */ this.selectedValue = selectedValue; /* 下拉框選項包含層 */ this.optionsContainer = optionsContainer; this._handleShowOptions(this.parentElement); this._unifyWidth(selectedOption); },
/* 顯示與隱藏事件 */ _handleShowOptions(element) { element.addEventListener('click', (e) => { let clickNode = e.target; this._unifyWidth(this.selectedOption); /* 點擊的是不是下拉框 */ if(this._isOptionNode(clickNode, this.selectedOption)) { if(this.downStatus) { this._hiddenDropDown(); } else { this._showDropDown(); } } else if(clickNode.className == 'optionsItem') { this._handleSelected(clickNode); } else { this._hiddenDropDown(); } }) }, /* 判斷是不是下拉框選項 */ _isOptionNode(clickNode, target) { if (!clickNode || clickNode === document) return false; return clickNode === target ? true : this._isOptionNode(clickNode.parentNode, target); }, /* 顯示下拉框選項 */ _showDropDown() { this.optionsContainer.style.transform = 'scale(1, 1)'; this.optionsContainer.style.opacity = '1'; this.selectedOption.className = 'selectedOption'; this.downStatus = true; }, /* 隱藏下拉框選項 */ _hiddenDropDown() { this.optionsContainer.style.transform = 'scale(1, 0)'; this.optionsContainer.style.opacity = '0'; this.selectedOption.className = 'selectedOption'; this.downStatus = false; },
/* 對每一個選項的點擊事件 */ _handleSelected(clickNode) { this.selectedValue.innerText = clickNode.innerText; clickNode.className = 'optionsItem itemSelected'; this._siblingsDom(clickNode, function(clickNode) { if(clickNode) { clickNode.className = 'optionsItem'; } }); this._hiddenDropDown(); }, /* 兄弟節點處理函數 */ _siblingsDom(clickNode, callback) { /* arguments 是一個對應於傳遞給函數的參數的類數組對象 * arguments對象是全部(非箭頭)函數中均可用的局部變量 * 包含傳遞給函數的每一個參數,第一個參數在索引0處 * arguments對象不是一個 Array,它相似於Array, * 但除了length屬性和索引元素以外沒有任何Array屬性 * */ (function (ele) { /* arguments.callee * 指向當前執行的函數 * */ callback(ele); if (ele && ele.previousSibling) { arguments.callee(ele.previousSibling); } })(clickNode.previousSibling); (function (ele) { callback(ele); if (ele && ele.nextSibling) { arguments.callee(ele.nextSibling); } })(clickNode.nextSibling); },
/* 判斷寬度 */ _unifyWidth(selectedOption) { /* 找到全部的li標籤 */ let optionsItem = document.querySelectorAll('.optionsItem'); let standardWidth = selectedOption.offsetWidth; /* 對每一個li標籤設置寬度 */ optionsItem.forEach((item) => { standardWidth = item.offsetWidth > standardWidth ? item.offsetWidth : standardWidth; item.style.width = standardWidth - 32 + 'px'; selectedOption.style.width = standardWidth + 'px'; }); }
(function() { /* 定義selector下拉框 */ let Selector = function(params) { /* 初始化 */ this._initSelector(params); }; Selector.prototype = { /* 將上面的方法所有放在Selector原型上 */ }; /* 掛載到window上*/ window.$Selector = Selector; })();
關於原型與原型鏈,能夠查看我記錄的 js面試
正在努力學習中,若對你的學習有幫助,留下你的印記唄(點個贊咯^_^)