2012.05.25 jq Tab

经过这段时间的奋斗,jq tab的基础功能已经在昨天完成,不包括样式。 到目前为止,算是完成了v0.1版本。

接下来要完成的功能包括:

1.设置要显示的item属性(现在每个数据单元被称为json)

2.添加样式,让这个jq tab好看一点,不过应该还是最先实现公司那种样式。

下面贴上这个基础版本的代码,包括演示html:

js:

这里引用了jquery 1.72 min文件,这个就自己下载去吧。

View Code
  1 /**
  2 * @author Steven
  3 先不考虑页面resize的情况,做好设置先
  4 */
  5 
  6 /*-------------- Common Functions ------------------*/
  7 function stopPropagation(e) {
  8     e = e || window.event;
  9     if (e.stopPropagation) { //W3C阻止冒泡方法
 10         e.stopPropagation();
 11     } else {
 12         e.cancelBubble = true; //IE阻止冒泡方法
 13     }
 14 }
 15 function removeEleFromArr(arr,obj) {
 16     if (!arr) {
 17         return false;
 18     }
 19     var removeIndexArr = [];
 20     for (var i = 0; i < arr.length; i++) {
 21         if (arr[i] == obj) {
 22             removeIndexArr.push(i);
 23         }
 24     }
 25     for (var i = removeIndexArr.length - 1; i >= 0; i--) {       
 26          arr.splice(removeIndexArr[i], 1);
 27     }
 28 }
 29 
 30 function removeArrFromArr(arr1, arr2) {
 31     if (!arr1 || !arr2) {
 32         return false;
 33     }
 34     var copyArr1 = arrayCopy(arr1);
 35     for (var i = 0; i < arr2.length; i++) {
 36         removeEleFromArr(copyArr1, arr2[i]);
 37     }
 38     return copyArr1;
 39 }
 40 
 41 function arrayCopy(arr) {
 42     if (!!arr && typeof arr.slice == "function") {
 43         return arr.slice();
 44     }
 45     else {
 46         return null;
 47     }
 48 }
 49 //window.onresize = function () {
 50 //    var me = jqTabMaster.prototype,
 51 //        config = me.config;
 52 //    config.isResize = true;
 53 //    alert("resize");
 54 //}
 55 
 56 /*--------------------------------------------------*/
 57 var jqTabMaster = function () {
 58 };
 59 jqTabMaster.prototype.config = {
 60     containerID: "",
 61     size: 0,
 62     items: [],
 63     allItemsIndex:[],
 64     showItemsIndex: [],
 65     notShowItemsIndex: [],
 66      "",
 67     callback: null
 68 };
 69 
 70 
 71 jqTabMaster.prototype.packingItems = function (items) {
 72     for (var i = 0; i < items.length; i++) {
 73         items[i]["__jqTabIndex"] = i;
 74     }
 75     return items;
 76 }
 77 jqTabMaster.prototype.getContinueousIndexArr = function (startIndex, endIndex) {
 78     var me = jqTabMaster.prototype,
 79          config = me.config,
 80          items = config.items,
 81          max = items.length - 1,
 82          startIndex = (typeof startIndex == 'undefined' || isNaN(startIndex)) ? 0 : startIndex,
 83          endIndex = (typeof endIndex == 'undefined' || isNaN(endIndex)) ? max : endIndex,
 84          indexArr = [];
 85 
 86     for (var i = startIndex; i <= endIndex; i++) {
 87         indexArr.push(i);
 88     }
 89     
 90     return indexArr;
 91 }
 92 // 传入需要显示的items的索引数组,根据该数组来显示
 93 jqTabMaster.prototype.buildUl = function (indexArr, className) {
 94     if (!indexArr) {
 95         return false;
 96     }
 97 
 98     var me = jqTabMaster.prototype,
 99         config = me.config,
100         items = config.items,
101         currentIndex,
102         callback = config.callback,
103         ul = document.createElement("ul"),
104         li;
105     
106     for (var i = 0; i < indexArr.length; i++) {
107         currentIndex = indexArr[i];
108       
109         li = document.createElement("li");
110         li.innerHTML = items[currentIndex].text;
111         li.index = items[currentIndex].__jqTabIndex;
112         ul.appendChild(li);
113     }
114     if (!!className) {
115         ul.className = className;
116     }
117 
118     me.bindTabsClickEvent(ul, callback);
119     return ul;
120 }
121 
122 jqTabMaster.prototype.bindTabsClickEvent = function (ul, callback) {
123     if (!!ul && ul.tagName == "UL" && typeof callback == "function") {
124         ul.onclick = function (ev) {
125             var ev = ev || window.event,
126                  target = ev.target || ev.srcElement,
127                  me = jqTabMaster.prototype,
128                  config = me.config,
129                  currentIndex;
130             if (target.tagName == "LI") {
131                 currentIndex = target.index;
132                 callback.call(this, config.items[currentIndex]);
133             }
134             else {
135                 return false;
136             }
137         }
138     }
139 }
140 jqTabMaster.prototype.unbindTabsClickEvent = function (ul) {
141     if (!!ul && ul.tagName == "UL" && typeof callback == "function") {
142         ul.onclick = null;
143     }
144 }
145 
146 jqTabMaster.prototype.initial = function (option) {
147     var me = jqTabMaster.prototype,
148         allItemsIndex = me.getContinueousIndexArr(0, option.items.length - 1);
149 
150     this.config.containerID = option.containerID;
151     this.config.size = option.size;
152     this.config.items = me.packingItems(option.items);
153     this.config.allItemsIndex = allItemsIndex;
154     this.config.width = option.width;
155     this.config.callback = option.callback;
156 
157     var container = $("#" + this.config.containerID),
158          iLen,
159          ul,
160          needShowIndexArr = [],
161          showItemsIndex = [],
162          moreItemsCount = 0;
163 
164     container.hide();
165     container.addClass('container');
166     container.css('width', this.config.width);
167     container.css('overflow', 'hidden');
168     /*增加”更多“按钮,默认为disabled*/
169     container.css({ 'width': '-=40px' });
170     var moreBtn = $("<div id='divMoreBtn' class='no-more'><span>更多</span></div>");
171     moreBtn.insertAfter(container);
172 
173     /* 添加可显示的tabs */
174     iLen = Math.min(this.config.items.length, this.config.size);
175     needShowIndexArr = me.getContinueousIndexArr(0, iLen - 1);
176     ul = me.buildUl(needShowIndexArr);
177     container.append(ul);
178 
179     container.show();
180     /* Get Real Size 
181     由于这里要调用offsetTop来判断是否超出边界,调用offset的参数会比较耗性能,
182     现在是用从头开始便利数组获取的,之后可以使用二分法来进行快速查找,以提高性能。
183     * */
184     var displayInfo = me.getRealDisplayInfo();
185     this.config.showItemsIndex = displayInfo.showItemsIndex;
186     this.config.notShowItemsIndex = displayInfo.notShowItemsIndex;
187 
188     /* 当tab没有完全显示时 */
189     if ((this.config.items.length - this.config.showItemsIndex.length) > 0) {
190         $("#divMoreBtn").toggleClass('no-more');
191         /*绑定显示更多tab事件*/
192         $("#divMoreBtn").bind('click', function (ev) {
193             me.showMoreTabs(ev);
194         });
195     }
196 }
197 
198 jqTabMaster.prototype.getRealDisplayInfo = function () {
199     var me = jqTabMaster.prototype,
200         config = me.config,
201         items = config.items,
202         lis = $("#" + config.containerID + " ul li"),
203         showItemsIndex = [],
204         allItemsIndex = me.config.allItemsIndex,
205         notShowItemsIndex = [],
206         originOffsetTop = null;
207 
208 
209     lis.each(function (i) {
210         if (originOffsetTop == null || originOffsetTop == this.offsetTop) {
211             originOffsetTop = this.offsetTop;
212             showItemsIndex.push(this.index);
213         }
214         else if (this.offsetTop != originOffsetTop) {
215             return false;
216         }
217     });
218 
219     notShowItemsIndex = removeArrFromArr(allItemsIndex, showItemsIndex);
220 
221     return { showItemsIndex: showItemsIndex, notShowItemsIndex: notShowItemsIndex };
222 }
223 
224 /*
225 * params:
226 * ev: window.event
227 * me: jqTabMaster.prototype
228 */
229 jqTabMaster.prototype.showMoreTabs = function (ev) {
230     var me = jqTabMaster.prototype,
231          config = me.config,
232          ev = ev || window.event,
233          target = $("#divMoreBtn"),
234     /* 需要显示的items索引数组 */
235          needShowIndexArr = [],
236     /* 容器的offset Left、top和尺寸信息 */
237          offset, offsetLeft, offsetTop,
238          width, height,
239     /* 弹出层的绝对坐标和宽度 */
240          moreX, moreY,
241          moreWidth,
242     /* 空隙值 */
243          spaceX = 10, spaceY = 5,
244     /* more tabs*/
245          ul;
246 
247     offset = target.offset();
248     offsetLeft = offset.left;
249     offsetTop = offset.top;
250     width = parseInt(target.css('width'));
251     height = parseInt(target.css('height'));
252 
253 
254     moreWidth = 200;
255     moreX = offsetLeft + width - moreWidth;
256     moreY = offsetTop + height + spaceY;
257     /* 这样计算能让弹出层的右边和more按钮的右边对齐*/
258     moreX < 0 && (moreWidth += (moreX - spaceX)) && (moreX = spaceX);
259 
260 
261     var moreDiv = $("<div>"),
262              moreTabsContainer = $("<div>"),
263              moreSetting = $("<div>");
264     moreDiv.attr('id', 'divMore');
265     moreDiv.addClass("more-div");
266     moreDiv.css({
267         'width': moreWidth + 'px',
268         'left': moreX + 'px',
269         'top': moreY + 'px'
270     });
271 
272     moreTabsContainer.addClass('more-tabs-container');
273 
274     needShowIndexArr = this.config.notShowItemsIndex;
275     ul = me.buildUl(needShowIndexArr);
276     moreTabsContainer.append(ul);
277 
278     moreSetting.addClass('more-setting');
279     moreSetting.html('设置');
280     moreSetting.toggle(
281              function () {
282                  this.innerHTML = "保存";
283                  var uls = $("#divMore ul,#" + config.containerID + " ul");
284                  for (var i = 0; i < uls.length; i++) {
285                      uls[i].onclick = null;
286                      me.buildSettingBtns(uls[i]);
287                  }
288                  me.unbindEventsWhenSettingTabs();
289              }, function () {
290                  this.innerHTML = "设置";
291                  var uls = $("#divMore ul,#" + config.containerID + " ul");
292                  uls.each(function (i) {
293                      me.bindTabsClickEvent(uls[i], me.config.callback);
294                      me.removeSettingBtns(uls[i]);
295                  });
296                  me.bindEventsWhenMoreTabsShow();
297              });
298 
299     moreDiv.append(moreTabsContainer).append(moreSetting);
300 
301     $(document.body).append(moreDiv);
302     stopPropagation(ev);
303 
304     /* more tabs显示后,重新绑定事件*/
305     me.bindEventsWhenMoreTabsShow();
306 
307     /*阻止选中文本*/
308     me.bankSelect();
309 }
310 jqTabMaster.prototype.hideMoreTabs = function () {
311     $("#divMore").remove();
312 
313     /* more tabs隐藏后重新绑定事件*/
314     jqTabMaster.prototype.bindEventsWhenMoreTabsHide();
315 }
316 jqTabMaster.prototype.unbindEventsWhenSettingTabs = function () {
317     $(document).unbind('click');
318     $("#divMoreBtn").unbind('click');
319 }
320 jqTabMaster.prototype.bindEventsWhenMoreTabsHide = function () {
321     $(document).unbind('click');
322     $("#divMoreBtn").unbind('click')
323      .bind('click', function () {
324          jqTabMaster.prototype.showMoreTabs();
325      });
326 }
327 jqTabMaster.prototype.bindEventsWhenMoreTabsShow = function () {
328     /* 刷新more按钮的click事件。再点击click时也隐藏more*/
329     $("#divMoreBtn").unbind('click')
330      .bind('click', function () {
331          jqTabMaster.prototype.hideMoreTabs();
332      }); ;
333 
334     /* 点击more tabs容器外地地方时,隐藏more tabs*/
335     $(document).unbind('click').bind('click', function (ev) {
336         var me = jqTabMaster.prototype,
337              ev = ev || window.event,
338              target = ev.target || ev.srcElement,
339              isDivMore = target.id == "divMore",
340              isBelong2DivMore = $(target).parents("#divMore").length > 0;
341 
342         if (!isBelong2DivMore) {
343             me.hideMoreTabs();
344         }
345         else {
346             stopPropagation(ev);
347             return false;
348         }
349     });
350 }
351 
352 jqTabMaster.prototype.buildSettingBtns = function (ul) {
353     if (!ul || ul.tagName != "UL") {
354         return false;
355     }
356 
357     var me = jqTabMaster.prototype,
358         config = me.config,
359         isBelong2DivMore = $(ul).parents("#divMore").length > 0,
360         isBelong2TabsContainer = $(ul).parents("#" + config.containerID).length > 0,
361         optType = isBelong2DivMore ? "add" : "remove",
362         lis = ul.getElementsByTagName("li"),
363         li,
364         iLen = lis.length,
365         spnOpt;
366 
367     for (var i = 0; i < iLen; i++) {
368         li = lis[i];
369         (function (li, me) {
370             me.bindSettingOpt(li, optType);
371         })(li, me);
372     }
373 }
374 jqTabMaster.prototype.bindSettingOpt = function (li, optType) {
375     var me = jqTabMaster.prototype,
376         spnOpt = document.createElement("span"),
377         className = "opt";
378 
379     spnOpt.className = className;
380     spnOpt.innerHTML = optType == "add" ? "+" : "-";
381 
382     if (optType == "add") {
383         spnOpt.onclick = function () {
384             me.addTab($(li)[0]);
385         }
386     }
387     else {
388         spnOpt.onclick = function () {
389             me.removeTab($(li)[0]);
390         }
391     };
392     $(li).append(spnOpt);
393 }
394 
395 jqTabMaster.prototype.removeSettingBtns = function (ul) {
396     if (!ul || ul.tagName != "UL") {
397         return false;
398     }
399 
400     var spnOpts = $(ul).find("li span");
401     spnOpts.remove();
402 }
403 
404 jqTabMaster.prototype.addTab = function (li) {
405     var me = jqTabMaster.prototype,
406         config = me.config,
407         maxSize = config.size,
408         realSize = config.showItemsIndex.length;
409 
410     if (realSize >= maxSize) {
411         return false;
412     }
413 
414     var showItemsIndex = config.showItemsIndex,
415         notShowItemsIndex = config.notShowItemsIndex,
416         items = config.items,
417         showedTabs = $("#" + config.containerID + " ul li"),
418         lastShowTab = realSize > 0 ? showedTabs.eq(realSize - 1) : null,
419         moreTabsUl = $("#divMore ul"),
420         moreTabsLi = moreTabsUl.find("li"),
421         newLi = document.createElement("li"),
422         currentLiIndex = li.index,
423         currentItem = items[currentLiIndex],
424         addSuccessful = false;
425 
426     /* Build New Li need to insert */
427     newLi.index = currentLiIndex;
428     newLi.innerHTML = currentItem.text;
429     newLi = $(newLi);
430     me.bindSettingOpt(newLi, "remove");
431 
432     if (!!lastShowTab) {
433         newLi.insertAfter(lastShowTab);
434     }
435     else {
436         $("#" + config.containerID + " ul").append(newLi);
437     }
438     addSuccessful = !lastShowTab || lastShowTab.offset().top == newLi.offset().top;
439     if (!addSuccessful) {
440         newLi.remove();
441     }
442     else {
443         showItemsIndex.push(currentLiIndex);
444         removeEleFromArr(notShowItemsIndex, currentLiIndex);
445         $(li).remove();
446     }
447 }
448 jqTabMaster.prototype.removeTab = function (li) {
449     var me = jqTabMaster.prototype,
450         config = me.config,
451         items = config.items,
452         showItemsIndex = config.showItemsIndex,
453         notShowItemsIndex = config.notShowItemsIndex,
454         realSize = config.showItemsIndex.length,
455 
456         showedTabs = $("#divMore ul li"),
457         lastShowTab = showedTabs.eq(notShowItemsIndex.length - 1),
458         currentLiIndex = li.index,
459         currentItem = items[currentLiIndex],
460         newLi = document.createElement("li"),
461         move2Index = 0;
462 
463     newLi.index = currentLiIndex;
464     newLi.innerHTML = currentItem.text;
465     newLi = $(newLi);
466     me.bindSettingOpt(newLi, "add");
467     
468     $(li).remove();
469     removeEleFromArr(showItemsIndex, currentLiIndex);
470    
471     newLi.insertAfter(lastShowTab);
472     notShowItemsIndex.push(currentLiIndex);
473 }
474 
475 jqTabMaster.prototype.getNotShowItemsIndex = function () { 
476     
477 }
478 jqTabMaster.prototype.getItemRank = function (num, arr) {
479     var me = jqTabMaster.prototype,
480         config = me.config,
481         showItemsIndex = config.showItemsIndex,
482         notShowItemsIndex = config.notShowItemsIndex,
483         items = config.items,
484         allItemsIndex = [];
485 
486     for (var i = 0; i < items.length; i++) {
487 
488     }
489 }
490 
491 /* 禁止文本被选中 */
492 jqTabMaster.prototype.bankSelect = function () {
493     $("#divMore,#divMoreBtn,#" + jqTabMaster.prototype.config.containerID).bind('selectstart', function () {
494         return false;
495     })
496      .css({
497          '-moz-user-select': 'none',
498          '-webkit-user-select': 'none',
499          'user-select': 'none'
500      });
501 }

css:

View Code
  1  div{
  2      border:solid 1px #000;    
  3  }
  4  
  5  .container{
  6      border:solid 1px #000;
  7      display:block;
  8      float:left;
  9      height:50px;    
 10      margin:0px;
 11      padding:0px;
 12  }
 13  
 14  .container ul{
 15      float:left;
 16      list-style:none;
 17      margin:12px 5px 5px 5px;
 18      padding:0px;
 19      text-align: left;
 20  }
 21  .container ul li{
 22      border:solid 1px #f00;
 23      display:inline-block;
 24      margin: 5px 5px 105px 5px;
 25      overflow:visible;
 26      text-align:center;
 27      width:40px;
 28      
 29  }
 30  
 31  #divMoreBtn{
 32      border:solid 1px #000;
 33      display:block;
 34      float:left;
 35      height:50px;
 36      margin:0px 0px 0px 5px;
 37      vertical-align:bottom;
 38      width:35px;
 39  }
 40  
 41  #divMoreBtn span{
 42      display:block;
 43      line-height:60px;    
 44      text-align:center;
 45      vertical-align:middle;
 46  }
 47  
 48  .no-more{
 49      background-color#111;
 50      color:#ddd;
 51  }
 52  .more{
 53      background-color:#fff;
 54      color:#000;
 55  }
 56  .more-div{
 57      height:420px;
 58      position:absolute;
 59  }
 60  .more-div .more-tabs-container{
 61      height:360px;
 62      margin:5px;
 63      overflow-x:none;
 64      overflow-y:auto;
 65      position:relative;
 66  }
 67  .more-div .more-setting{
 68      color:#f00;
 69      display:block;
 70      font-weight:bold;
 71      line-height:40px;
 72      margin:8px 5px;
 73      height:40px;
 74      text-align:center;
 75      position:relative;
 76      vertical-align: bottom;
 77  }
 78  
 79  .more-tabs-container ul{
 80      margin:0px;
 81      padding: 0px;
 82      clear:both;
 83      float:left;
 84      list-style:none;    
 85  }
 86  
 87  .more-tabs-container ul li{
 88      border:solid 1px #DDDDDD;
 89      display:block;
 90      list-style:none;
 91      line-height:30px;    
 92      height:30px;
 93      margin:2px 10px 5px 10px;
 94      text-align:center;
 95      vertical-align:middle;
 96      width:120px;
 97  }
 98  .opt
 99  {
100      border:solid #333333 1px; 
101      color:red;
102      cursor:pointer;
103      display:inline-block;
104      float:right;
105      font-weight:bold;
106      height:13px;
107      margin:2px 1px;
108      line-height:13px;
109      vertical-align:middle;
110      width:10px;
111  }

html:

View Code
 1  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 2  "http://www.w3.org/TR/html4/loose.dtd">
 3  <html xmlns="http://www.w3.org/1999/xhtml">
 4      <head>
 5          <meta http-equiv="Content-Type" content="text/html; charset=gbk2312" />
 6          <title>Jq Tab Demo</title>
 7          <link href="css/jqTab.css" rel="stylesheet"  />
 8      </head>
 9      <body>
10          <h1>jq Tab</h1>
11          
12          
13          <div id="div1">                 
14          </div>
15          <script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
16          <script type="text/javascript" src="js/jqTab.js"></script>
17          <script type="text/javascript">
18              var jqTab = new jqTabMaster();
19              jqTab.initial({
20                  containerID: "div1",
21                  size: 6,
22                  items: [
23                      { value: "1", text: "1" },
24                      { value: "2", text: "2" },
25                      { value: "3", text: "3" },
26                      { value: "4", text: "4" },
27                      { value: "5", text: "5" },
28                      { value: "6", text: "6" },
29                      { value: "7", text: "7" },
30                      { value: "8", text: "8" },
31                      { value: "9", text: "9" },
32                      { value: "10", text: "10" }
33                  ],
34                   "50%",
35                  callback: callback
36              });
37              function callback(data) {
38                  alert(data.__jqTabIndex);
39              }
40              
41          </script>
42      </body>
43  </html>

                                                              这篇就这么多。 补2012.05.25

原文地址:https://www.cnblogs.com/bee0060/p/2519123.html