以前作項目時常常用到一種觸點式彈出菜單或者導航的功能,這個功能的主要應用場景是:web頁面中多層分級導航或者子功能目錄,但又考慮到頁面區域有限,因而就考慮到在鼠標移動到某導航按鈕上或者點擊時,系統將在該按鈕下浮動一個層,展示子導航或者子目錄,當用戶選擇這些子目錄/導航時,頁面做出相應的操做,這種功能從人機交互和頁面佈局上都有很好的人性化體驗。最近有些閒暇時間,將此功能從新整理並封裝,造成一個公共插件,命名爲:SelectItem.js,分享以下:web
插件的主要實現的功能:數組
1. 功能模塊化封裝,提供一個對外的初始化接口供應用調用便可,首先須要綁定一個頁面觸發元素(連接/按鈕等),傳入元素id;閉包
2. 提供子菜單/導航條目的初始化入口,調用方法輸入須要初始化的條目數組,以參數方式輸入; app
3. 提供對外事件接口,如點擊子菜單/導航的事件定義等,供調用方自定義事件實現;ide
4. 提供輔助添加功能,若是子菜單是選擇信息,而初始化的條目又不符合調用需求,則需提供讓給調用方自定義條目的功能,此輔助功能能夠根據須要進行屏蔽;模塊化
效果圖以下:(左側爲帶自定義輔助功能的效果,右側爲不帶自定義輔助功能的效果)函數
上述效果調用時的代碼以下:佈局
1 AutoDiv("btn", false).InitControl([ 2 { 3 key: "12", 4 value: "二個選項(A | B)" 5 }, 6 { 7 key: "13", 8 value: "三個選項(A | B | C)" 9 }, 10 { 11 key: "14", 12 value: "四個選項(A | B | C | D)" 13 }, 14 { 15 key: "15", 16 value: "五個選項(A | B | C | D | E)" 17 }, 18 { 19 key: "0", 20 value: "自定義選項類型" 21 } 22 ], 23 function(value) { 24 //處理選中類型 25 alert(value); 26 }, 27 function() { 28 //打開自定義選項建立窗口 29 alert("new dialog."); 30 }); 31 }
能夠看出,在頁面中引用該js文件,而後對須要觸點彈出的頁面元素進行插件綁定便可,其中綁定函數AutoDiv("btn", false)有兩個參數,第一個參數是須要綁定的頁面元素id,第二個參數是個布爾值,須要自定義輔助功能時傳遞true,不然傳遞false。綁定好頁面元素後,接下來是鏈式調用過程,函數InitControl有三個參數,第一個參數是須要展示的菜單項,它是一個鍵值對數組(key爲選擇項的反饋表示,value爲菜單項顯示信息);第二個參數是菜單項選擇點擊事件的實現,由調用方定義實現,函數有一個參數,即所選菜單項的key值;第三個參數是自定義輔助事件的實現,一樣由調用方定義實現。
this
控件源碼以下:spa
1 /* 2 * write by zhangyu,2013-07-09,v1.0 3 * 4 * 實現觸點式菜單彈出及選擇功能 5 * 6 */ 7 8 function AutoDiv(id, allowNewFlag) { 9 //預留退路 10 if (!document.getElementById) return false; 11 if (!document.createElement) return false; 12 13 //保存當前上下文 14 var me = this; 15 16 me.targetControlID; //定義當前綁定的id及其對象 17 me.targetObj = null; 18 me.pupDivObj = null; //定義彈出浮動層對象 19 me.callBackFun = null; //選中事件 20 me.callBackNewFun = null; //自定義回調事件 21 me.isFocusIn = false; //標記浮動層是否是處於鼠標焦點內 22 me.allowNewFlag = false; //標記是否顯示自定義選項類型選項 23 me.currentIndex = -1; //當前選中的結果索引 24 me.LastIndex = -1; //上一條選中的結果索引 25 26 me.Result; //最後結果‘13’、‘14’、‘15’、‘21’、‘31’ 27 28 if (id != null && typeof (id) != undefined && id != "") { 29 if (!document.getElementById(id)) return false; 30 //賦值類的成員 31 me.targetControlID = id; 32 me.targetObj = document.getElementById(id); 33 } 34 35 if (allowNewFlag != null && typeof (allowNewFlag) != undefined && allowNewFlag != "") { 36 37 me.allowNewFlag = allowNewFlag; 38 } 39 40 if (me.pupDivObj == null || typeof (me.pupDivObj) == undefined) { 41 42 me.pupDivObj = document.createElement("div"); 43 me.pupDivObj.setAttribute("class", "pupDiv"); 44 //加載新建的div對象到文檔中去 45 var parent = document.getElementById(me.targetControlID).parentNode; 46 if (parent != null && typeof (parent) != undefined) { 47 parent.appendChild(me.pupDivObj); 48 } 49 } 50 //浮動層彈出展示事件 51 me.pubDiv = function() { 52 me.pupDivObj.style.display = "block"; 53 me.pupDivObj.style.backgroundColor = "#ffffff"; 54 me.pupDivObj.style.position = "absolute"; 55 me.pupDivObj.style.top = me.targetObj.getBoundingClientRect().top + 20; 56 me.pupDivObj.style.left = me.targetObj.getBoundingClientRect().left; 57 me.pupDivObj.style.width = "150"; 58 //綁定內容 59 me.pupDivObj.innerHTML = me.GetContentTable(); 60 //定義行事件 61 var result = me.pupDivObj.getElementsByTagName("td"); 62 if (result.length > 0) { 63 //給每一個Td動態綁定事件(新建了一個閉包,用來傳遞參數,不然全部元素的一下三個鼠標事件的參數i會是相同的值) 64 for (var i = 0; i < result.length; i++) { 65 var bb = new BiBaoOnMouseResult(i, me); 66 AddEvent(result[i], "mouseover", bb.OnMouseOverEx); 67 AddEvent(result[i], "mouseout", bb.OnMouseOutEx); 68 AddEvent(result[i], "click", bb.OnMouseClickEx); 69 } 70 } 71 } 72 //類型選項綁定函數 73 me.GetContentTable = function() { 74 var DivContent = "<table cellSpacing='0' cellPadding='1' align='center' border='0' id='DivContent_Table'>"; 75 for (var i = 0; i < me.itemList.length - 1; i++) { 76 DivContent += " <tr ReturnValue='" + me.itemList[i].key + "' name='row'>" 77 + " <td height='15' nowrap>" 78 + " <div style='width:" + (me.pupDivObj.offsetWidth - 12) + ";' class='listOption' title='" + me.FliterString(me.itemList[i].value) + "'>" + me.FliterString(me.itemList[i].value) + "<div>" 79 + " </td>" 80 + " </tr>"; 81 } 82 //添加自定義選項 83 if (me.allowNewFlag) { 84 DivContent += " <tr ReturnValue='" + me.itemList[me.itemList.length - 1].key + "' name='line'>" 85 + " <td nowrap>" 86 + " <div style='font-size:1px; border-top:solid 1px #dde0e0; height:3px;'></div>" 87 + " </td>" 88 + " </tr>" 89 + " <tr ReturnValue='" + me.itemList[me.itemList.length - 1].key + "' name='row'>" 90 + " <td height='15' nowrap>" 91 + " <div style='width:" + (me.pupDivObj.offsetWidth - 12) + ";' class='listOption' title='" + me.FliterString(me.itemList[me.itemList.length - 1].value) + "'>" + me.FliterString(me.itemList[me.itemList.length - 1].value) + "<div>" 92 + " </td>" 93 + " </tr>"; 94 } 95 DivContent += "</table>"; 96 return DivContent; 97 } 98 //定義過濾函數 99 me.FliterString = function(orgString) { 100 orgString = orgString.replace(new RegExp("\"", "gi"), """); 101 orgString = orgString.replace(new RegExp("'", "gi"), "'"); 102 return orgString; 103 } 104 //綁定觸發控件的click事件 105 AddEvent(me.targetObj, "click", function() { 106 me.pubDiv(); 107 }); 108 //綁定浮動層的事件 109 AddEvent(me.pupDivObj, "mouseover", function() { 110 me.isFocusIn = true; 111 }); 112 AddEvent(me.pupDivObj, "mouseout", function() { 113 me.isFocusIn = false; 114 }); 115 //隱藏彈出層 116 me.Hide = function() { 117 me.pupDivObj.style.display = "none"; 118 me.currentIndex = -1; 119 } 120 //下拉菜單的鼠標事件 121 me.OnTdMouseOver = function(i) { 122 me.currentIndex = i; 123 var result = me.pupDivObj.firstChild; 124 result.rows[me.currentIndex].style.cursor = "point"; 125 if (!result || result.rows.length <= 0) 126 return; 127 if (result.rows[me.currentIndex] != undefined && result.rows[me.currentIndex].name != "line") { 128 129 //取消以前選中項的顏色 130 if (result.rows[me.LastIndex] != null) { 131 result.rows[me.LastIndex].style.backgroundColor = "#FFFFFF"; 132 result.rows[me.LastIndex].style.color = "#000000"; 133 } 134 //改變選中項的顏色 135 if (result.rows[me.currentIndex] != undefined) { 136 result.rows[me.currentIndex].style.backgroundColor = "gray"; //"#3161CE"; 137 result.rows[me.currentIndex].style.color = "#FFFFFF"; 138 } 139 me.LastIndex = me.currentIndex; 140 } 141 } 142 me.OnTdMouseOut = function(i) { 143 var result = me.pupDivObj.firstChild; 144 if (!result || result.rows.length <= 0) 145 return; 146 if (result.rows[me.currentIndex] != undefined && result.rows[me.currentIndex].name != "line") { 147 148 result.rows[me.currentIndex].style.backgroundColor = "#FFFFFF"; 149 result.rows[me.currentIndex].style.color = "#000000"; 150 } 151 } 152 me.OnTdMouseClick = function(i) { 153 var evt = evt || window.event; 154 var result = me.pupDivObj.firstChild; 155 if (!result || result.rows.length <= 0) 156 return; 157 if (result.rows[me.currentIndex].name != "line") { 158 159 //給輸入框賦值 160 me.Result = result.rows[me.currentIndex].getAttribute("ReturnValue"); 161 //隱藏搜索結果 162 me.pupDivObj.style.display = "none"; 163 me.currentIndex = -1; 164 //觸發外部事件 165 if (me.Result == "0") { 166 //自定義 167 me.callBackNewFun(); 168 } 169 else { 170 me.callBackFun(me.Result); 171 } 172 } 173 } 174 //綁定控件失去焦點事件 175 AddEvent(me.targetObj, "blur", function() { 176 if (!me.isFocusIn) { 177 me.Hide(); 178 } 179 }); 180 //初始化事件函數 181 me.InitControl = function(itemList, callBackFun, callBackNewFun) { 182 //須要綁定的選項 183 if (itemList.length > 0) { 184 me.itemList = itemList; 185 } 186 else { me.itemList = []; } 187 //初始化選項的點擊函數 188 if (me.callBackFun == null || typeof (me.callBackFun) == undefined) { 189 me.callBackFun = callBackFun; 190 } 191 //初始化新建選項的點擊函數 192 if (me.callBackNewFun == null || typeof (me.callBackNewFun) == undefined) { 193 me.callBackNewFun = callBackNewFun; 194 } 195 } 196 //添加對象事件 197 function AddEvent(target, eventType, callback) { 198 DeleteEvent(target, eventType, callback); 199 if (target.addEventListener) { 200 target.addEventListener(eventType, callback, false); 201 } 202 else { 203 //ie 204 target.attachEvent("on" + eventType, function(event) { return callback.call(target, event); }); 205 } 206 } 207 //刪除對象事件 208 function DeleteEvent(target, eventType, callback) { 209 if (target.removeEventListener) { 210 target.removeEventListener(eventType, callback, true); 211 } 212 else { 213 //ie 214 target.detachEvent("on" + eventType, callback); 215 } 216 } 217 //返回對象 218 return me; 219 }; 220 /* 221 * 新建一個閉包,用於實現鼠標點擊搜索結果時的事件,以解決經過訓練傳遞的參數一直是最後一個索引的問題 222 * 223 * writter:zhangyu 2012-01-03 224 */ 225 function BiBaoOnMouseResult(i, me) { 226 this.OnMouseClickEx = function() { 227 me.OnTdMouseClick(i); 228 }; 229 this.OnMouseOverEx = function() { 230 me.OnTdMouseOver(i); 231 }; 232 this.OnMouseOutEx = function() { 233 me.OnTdMouseOut(i); 234 }; 235 }
點擊這裏下載源碼