2012.05.21 jq Tab
昨天星期天,玩了一天,晚上看了需求文档,所以没有花时间学习。
今天继续实现jq tab。
根据之前的进度,剩余的工作量包括:
1.提供callback函数接口(完成)
2.样式(实在非我所长。这个带回公司再用公司的样式加以调整)
3.调整应该显示的tabs,数量不超过size(实现了添加设置按钮,还剩下添加加减符号,并实现从默认显示的tab和更多tab之间添加移除tab,相当于已实现三分之一)
4.每个tab可以接受任意数据格式(未实现,这个想过,难度应该不大。)
这里的callback函数接口,也是记录在config中,在初始化时传入。在创建ul时,会判断callback函数是否被正确传入,是的话,用callback.call(this, li.value)实现。
暂时callback函数只能接受li的value属性。 当功能修改成可以接受任意数据格式后,这个callback函数会接受li对应的json对象。
贴上代码和css,方便回公司修改:
js:

1 /** 2 * @author Steven 3 */ 4 5 /*-------------- Common Functions ------------------*/ 6 function stopPropagation(e) { 7 e = e || window.event; 8 if(e.stopPropagation) { //W3C阻止冒泡方法 9 e.stopPropagation(); 10 } else { 11 e.cancelBubble = true; //IE阻止冒泡方法 12 } 13 } 14 15 16 /*--------------------------------------------------*/ 17 var jqTabMaster = function(){ 18 }; 19 jqTabMaster.prototype.config = { 20 containerID:"", 21 size:0, 22 realSize:0, 23 items:[], 24 showItems:[], 25 width:"", 26 callback:null 27 }; 28 29 jqTabMaster.prototype.buildUl = function(startIndex, endIndex, className){ 30 var me = jqTabMaster.prototype, 31 config = me.config, 32 items = config.items, 33 callback = config.callback, 34 max = items.length-1, 35 startIndex = (typeof startindex =='undefined' || isNaN(startIndex))? 0:startIndex, 36 endIndex = (typeof endIndex =='undefined' || isNaN(endIndex))? max:endIndex, 37 ul = document.createElement("ul"), 38 li; 39 40 for(var i =startIndex;i<=endIndex;i++){ 41 li = document.createElement("li"); 42 li.innerHTML = items[i].text; 43 li.value = items[i].value; 44 ul.appendChild(li); 45 } 46 if(!!className){ 47 ul.className = className; 48 } 49 50 me.bindTabsClickEvent(ul,callback); 51 return ul; 52 } 53 54 jqTabMaster.prototype.bindTabsClickEvent = function(ul,callback){ 55 if(!!ul && ul.tagName=="UL" && typeof callback =="function"){ 56 ul.onclick = function(ev){ 57 var ev = ev || window.event, 58 target = ev.target || ev.srcElement; 59 if(target.tagName == "LI"){ 60 callback.call(this, target.value); 61 } 62 else 63 { 64 return false; 65 } 66 } 67 } 68 } 69 jqTabMaster.prototype.unbindTabsClickEvent = function(ul){ 70 if(!!ul && ul.tagName=="UL" && typeof callback =="function"){ 71 ul.onclick = null; 72 } 73 } 74 75 jqTabMaster.prototype.initial = function(option){ 76 this.config.containerID = option.containerID; 77 this.config.size = option.size; 78 this.config.items = option.items; 79 this.config.width = option.width; 80 this.config.callback = option.callback; 81 82 var me = jqTabMaster.prototype, 83 container = $("#"+this.config.containerID), 84 iLen, 85 ul, 86 showItems = [], 87 moreItemsCount = 0; 88 89 container.hide(); 90 container.addClass('container'); 91 container.css('width',this.config.width); 92 container.css('overflow','hidden'); 93 /*增加”更多“按钮,默认为disabled*/ 94 container.css({'width':'-=40px'}); 95 var moreBtn = $("<div id='divMoreBtn' class='no-more'><span>更多</span></div>"); 96 moreBtn.insertAfter(container); 97 98 /* 添加可显示的tabs */ 99 iLen = Math.min(this.config.items.length,this.config.size); 100 ul = jqTabMaster.prototype.buildUl(0, iLen); 101 container.append(ul); 102 103 container.show(); 104 /* Get Real Size 105 由于这里要调用offsetTop来判断是否超出边界,调用offset的参数会比较耗性能, 106 现在是用从头开始便利数组获取的,之后可以使用二分法来进行快速查找,以提高性能。 107 * */ 108 var displayInfo = me.getRealDisplayInfo(); 109 this.config.realSize = displayInfo.realSize; 110 this.config.showItems = displayInfo.showItems; 111 112 /* 当tab没有完全显示时 */ 113 if((this.config.items.length - this.config.realSize)>0){ 114 $("#divMoreBtn").toggleClass('no-more'); 115 /*绑定显示更多tab事件*/ 116 $("#divMoreBtn").bind('click',function(ev){ 117 me.showMoreTabs(ev); 118 }); 119 } 120 } 121 122 jqTabMaster.prototype.getRealDisplayInfo = function(){ 123 var me = jqTabMaster.prototype, 124 config = me.config, 125 realSize = 0, 126 lis = $("#"+config.containerID+" ul li"), 127 showItems = [], 128 originOffsetTop=null; 129 130 lis.each(function(i){ 131 if(originOffsetTop==null){ 132 originOffsetTop = this.offsetTop; 133 showItems.push(i); 134 } else if( this.offsetTop!=originOffsetTop){ 135 return false; 136 } 137 realSize++; 138 }); 139 return {realSize:realSize,showItems:showItems}; 140 } 141 142 /* 143 * params: 144 * ev: window.event 145 * me: jqTabMaster.prototype 146 */ 147 jqTabMaster.prototype.showMoreTabs = function(ev){ 148 var me = jqTabMaster.prototype, 149 config = me.config, 150 ev = ev || window.event, 151 target = $("#divMoreBtn"), 152 /* 容器的offset Left、top和尺寸信息 */ 153 offset, offsetLeft, offsetTop, 154 width, height, 155 /* 弹出层的绝对坐标和宽度 */ 156 moreX, moreY, 157 moreWidth, 158 /* 空隙值 */ 159 spaceX=10, spaceY=5, 160 /* more tabs*/ 161 ul; 162 163 offset = target.offset(); 164 offsetLeft = offset.left; 165 offsetTop =offset.top; 166 width = parseInt(target.css('width')); 167 height = parseInt(target.css('height')); 168 169 170 moreWidth = 200; 171 moreX = offsetLeft + width - moreWidth; 172 moreY = offsetTop + height + spaceY; 173 /* 这样计算能让弹出层的右边和more按钮的右边对齐*/ 174 moreX < 0 && (moreWidth += (moreX - spaceX)) && (moreX = spaceX); 175 176 //alert(offsetTop+" "+moreY+" "+height); 177 var moreDiv = $("<div>"), 178 moreTabsContainer = $("<div>"), 179 moreSetting = $("<div>"); 180 moreDiv.attr('id','divMore'); 181 moreDiv.addClass("more-div"); 182 moreDiv.css({ 183 'width':moreWidth+'px', 184 'left':moreX+'px', 185 'top':moreY+'px' 186 }); 187 188 moreTabsContainer.addClass('more-tabs-container'); 189 ul = me.buildUl(me.config.realSize); 190 moreTabsContainer.append(ul); 191 192 moreSetting.addClass('more-setting'); 193 moreSetting.html('设置'); 194 moreSetting.toggle( 195 function(){ 196 this.innerHTML = "保存"; 197 var uls = $("#divMore ul,#"+config.containerID+" ul"); 198 for(var i =0;i<uls.length;i++){ 199 uls[i].onclick=null; 200 } 201 me.unbindEventsWhenSettingTabs(); 202 },function(){ 203 this.innerHTML = "设置"; 204 var uls = $("#divMore ul,#"+config.containerID+" ul"); 205 uls.each(function(i){ 206 me.bindTabsClickEvent(uls[i]); 207 }); 208 me.bindEventsWhenMoreTabsShow(); 209 }); 210 211 moreDiv.append(moreTabsContainer).append(moreSetting); 212 213 $(document.body).append(moreDiv); 214 stopPropagation(ev); 215 216 /* more tabs显示后,重新绑定事件*/ 217 me.bindEventsWhenMoreTabsShow(); 218 219 /*阻止选中文本*/ 220 me.bankSelect(); 221 } 222 jqTabMaster.prototype.hideMoreTabs = function(){ 223 $("#divMore").remove(); 224 225 /* more tabs隐藏后重新绑定事件*/ 226 jqTabMaster.prototype.bindEventsWhenMoreTabsHide(); 227 } 228 jqTabMaster.prototype.unbindEventsWhenSettingTabs = function(){ 229 $(document).unbind('click'); 230 $("#divMoreBtn").unbind('click'); 231 } 232 jqTabMaster.prototype.bindEventsWhenMoreTabsHide = function(){ 233 $(document).unbind('click'); 234 $("#divMoreBtn").unbind('click') 235 .bind('click',function(){ 236 jqTabMaster.prototype.showMoreTabs(); 237 }); 238 } 239 jqTabMaster.prototype.bindEventsWhenMoreTabsShow = function(){ 240 /* 刷新more按钮的click事件。再点击click时也隐藏more*/ 241 $("#divMoreBtn").unbind('click') 242 .bind('click',function(){ 243 jqTabMaster.prototype.hideMoreTabs(); 244 });; 245 246 /* 点击more tabs容器外地地方时,隐藏more tabs*/ 247 $(document).unbind('click').bind('click', function(ev){ 248 var me = jqTabMaster.prototype, 249 ev = ev || window.event, 250 target = ev.target||ev.srcElement, 251 isDivMore = target.id=="divMore", 252 isBelong2DivMore = $(target).parents("#divMore").length>0; 253 254 if(!isBelong2DivMore){ 255 me.hideMoreTabs(); 256 } 257 else { 258 stopPropagation(ev); 259 return false; 260 } 261 }); 262 } 263 264 jqTabMaster.prototype.bankSelect = function(){ 265 $("#divMore,#divMoreBtn,#"+jqTabMaster.prototype.config.containerID).bind('selectstart',function(){ 266 return false; 267 }) 268 .css({ 269 '-moz-user-select':'none', 270 '-webkit-user-select':'none', 271 'user-select':'none' 272 }); 273 }
css:

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 }
html:

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=utf-8" /> 6 <title>Jq Tab Demo</title> 7 <link href="css/css.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.1.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:7, 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 width:"300px", 35 callback:callback 36 }); 37 function callback(value){ 38 alert(value); 39 } 40 41 </script> 42 </body> 43 </html>
今天就到这里
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了