我的开源框架之TAB控件
需求
(1)支持iframe、html、json格式的tab内容远程请求
(2)支持动态添加tab
(3)支持远程加载完成监听,支持tab激活事件监听
(4)支持reload tab内容【如果是远程加载】
(5)支持邮件菜单【未实现】
实现图例
客户代码
1 <body> 2 <div id="text"> 3 <h3>无题</h3> 4 <p>月落湖面两清影,</p> 5 <p>岸柳丝丝弄轻盈。</p> 6 <p>此番凉意写不出,</p> 7 <p>难画秋月一片晴。</p> </div> 8 <div style="padding-left:100px; padding-bottom:12px;"> 9 <div id="tabContainer" style="width:800px;height:260px"> 10 <div title="静态html" closable="true" >项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1项目1</div> 11 <div title="iframe加载" isiframe="true" url="/innerpage.html" iconcls="icon-edit" closable="true"> 12 </div> 13 <div title="远程HTML加载" dataType="html" url="/content.html" iconcls="icon-save" closable="true"> 14 </div> 15 </div> 16 </div> 17 <script type="text/javascript"> 18 var tabs; 19 $(function () { 20 tabs = $("#tabContainer").tabs({ 21 items: [{ 22 title: '远程加载JSON数据', 23 closable: false, 24 iconcls: 'icon-print', 25 actived: true,// 激活状态 26 url: 'testServer/jsonQuestTest.ashx',//如果不配置采用公用 $.fn.tabs.defaults里的配置 27 dataType: 'json'// //如果不配置采用公用 $.fn.tabs.defaults里的配置 28 },{ 29 title: '文本测试', 30 closable: false, 31 iconcls: 'icon-back', 32 actived: false,// 激活状态 33 content: $("#text") //'<a>我是测试内容.....................</a>'// 可以是文本,可以是$("#id")对象 34 }], 35 onLoadSuccess: function (title, context) { 36 console.log(title + "加载完成"); 37 if (title == "远程加载JSON数据" || title == "动态添加tab") { 38 context.target.html(JSON.stringify(context.data)); 39 } 40 }, 41 activedHandler: function (tilte,context) { 42 console.log("actived=" + tilte); 43 }, 44 closedHandler: function (title) { 45 console.log("closed=" + title); 46 } 47 }); 48 }); 49 function addTab() { 50 tabs.tabs("addTabs", { 51 title: '动态添加tab', 52 closable: true, 53 iconcls: 'icon-back', 54 actived: false,// 激活状态 55 //content: '<a>我是动态tab内容</a>' 56 url: 'testServer/jsonQuestTest.ashx',//如果不配置采用公用 $.fn.tabs.defaults里的配置 57 dataType: 'json',// //如果不配置采用公用 $.fn.tabs.defaults里的配置 58 onLoadSuccess: function (title, context) { 59 context.target.html(title+"loadsucc;我自己注册的事件 "+JSON.stringify(context.data)); 60 } 61 }); 62 } 63 function getSelectedTab() { 64 var res = tabs.tabs("getSelectedTab"); 65 alert(res.titleObj.attr("title")); 66 } 67 function reload() { 68 var itemsopt = $("#itemsopt").children("option[selected]"); 69 tabs.tabs("reLoadTab", itemsopt.val()); 70 if (tabs.tabs("isExist", itemsopt.val())) { 71 console.log(itemsopt.val()+"exist"); 72 } else { 73 console.log(itemsopt.val() + "no exist"); 74 } 75 76 } 77 </script> 78 </body>
组件代码
1 /************************************************************** 2 *作者:hjwen 3 *电邮:hjwen88@126.com 4 *版本:1.0 5 *版权许可:中国通用开源许可协议V1.0 6 *说明:myui组件tabs组件 7 ***************************************************************/ 8 (function ($) { 9 /****** 10 *渲染目标:renderHtml为构建html结构的函数,init初始化会调用 11 *******/ 12 var contentPadding = 6; 13 var showTitleItem = null; 14 var showContentItem = null; 15 var itemTitleContainer, itemContentContainer, existItems; 16 var headerWith = 0; 17 var itemsWidth = 0; 18 var leftMoreBtn = null, rightMoreBtn = null; 19 function renderHtml(target, opts) { 20 itemContentContainer = target; 21 var panel = target.panel({ expandable: false, maximizable: false, closeable: false, expanded: false }); 22 var titleWrap = target.prev("div"); 23 headerWith = titleWrap.width(); 24 var panelTitle = titleWrap.children(".panel-tilte"); 25 itemTitleContainer = $("<ul class=\"tabsul\"></ul>").appendTo(panelTitle); 26 target.css({ "overflow": "hidden", "padding": "0px" }); 27 existItems.css({ "width": target.width() - contentPadding * 2 + "px", "height": target.height() - contentPadding * 2 + "px", "margin": "0px", "padding": contentPadding + "px", "overflow": "auto" }).hide(); 28 createTabs(opts.items); 29 existItems = null; 30 }; 31 /**********私有方法开始********************/ 32 function createTabs(items) { 33 $.each(items, function (i, item) { 34 createTab(item, i); 35 }); 36 showContentItem.show(); 37 showTitleItem.attr("actived", "true").children("a").addClass("tabs_selected").css("border-bottom", "1px solid #FFFFFF"); 38 } 39 function createTab(item, index) { 40 //创建tab标题项 41 var a_tag = "<a href='javascript:void(0)'>"; 42 if (item.iconcls != '') 43 a_tag = a_tag + "<span class='item_title_ioc " + item.iconcls + "'></span>"; 44 if (item.closable) 45 a_tag = a_tag + "<span class='item_title_text'>" + item.title + "</span><span for=" + index + " class='item_title_close' ></span></a>"; 46 else 47 a_tag = a_tag + "<span class='item_title_text'>" + item.title + "</span></a>"; 48 var itemTitleLi = $("<li contextmenu=\"" + item.contextMenu + "\" datatype=\"" + item.dataType + "\" url=\"" + item.url + "\" isiframe=\"" + item.isiframe + "\" title=\"" + item.title + "\" closable=\"" + item.closable + "\" actived=\"" + item.actived + "\" for=" + index + ">" + a_tag + "</li>").appendTo(itemTitleContainer); 49 itemTitleLi.bind({ 50 "click": function () { 51 var $this = $(this); 52 if ($this.attr("actived") == "true") 53 return; 54 var idx = $this.attr("for"); 55 showContentItem.hide(); 56 showTitleItem.attr("actived", "false").children("a").removeClass("tabs_selected").css("border-bottom", "1px solid #99BBE8"); 57 $.each(itemContentContainer.children("div"), function (j, obj) { 58 var $obj = $(obj); 59 if (j == parseInt(idx)) { 60 $this.attr("actived", "true").children("a").addClass("tabs_selected").css("border-bottom", "1px solid #FFFFFF"); 61 showContentItem = $obj.show(); 62 showTitleItem = $this; 63 } 64 }); 65 if (item.activedHandler != null) { 66 item.activedHandler(showTitleItem.attr("title"), { titleObj: showTitleItem, conetentObj: showContentItem }); 67 } 68 } 69 }); 70 //如果可以关闭 71 if (item.closable) { 72 itemTitleLi.children("a").children(".item_title_close").bind({ 73 click: function () { 74 var allIts = itemContentContainer.children("div"); 75 var $t = $(this); 76 var foridx = parseInt($t.attr("for")); 77 var removeContent = null; 78 for (var k = 0, len = allIts.length; k < len; ++k) { 79 if (foridx == k) { 80 removeContent = $(allIts[k]); 81 break; 82 } 83 }; 84 //如果关闭的是激活的tab,则需要调整激活的tab 85 var showIdx = 0; 86 var titleLi = $t.parent("a").parent("li"); 87 if (titleLi.attr("actived") == "true") { 88 var showIt = titleLi.prev("li"); 89 showIdx = foridx - 1; 90 if (showIt.length == 0) { 91 showIt = titleLi.next("li"); 92 showIdx = foridx + 1; 93 } 94 showTitleItem = showIt; 95 showTitleItem.attr("actived", "true").children("a").addClass("tabs_selected").css("border-bottom", "1px solid #FFFFFF"); 96 //激活对应的内容div 97 for (var k = 0, len = allIts.length; k < len; ++k) { 98 if (showIdx == k) { 99 $(allIts[k]).show(); 100 break; 101 } 102 }; 103 } 104 //修改删除项目后面所有li项的for属性 105 var nextAll = titleLi.nextAll(); 106 if (nextAll.length > 0) { 107 setTimeout(function () { 108 $.each(nextAll, function (j, obj) { 109 var $obj = $(obj); 110 var curFor = parseInt($obj.attr("for")); 111 var newFor = curFor - 1; 112 $obj.attr("for", newFor); 113 $obj.children("a").children(".item_title_close").attr("for", newFor); 114 }); 115 }, 0); 116 } 117 var title = titleLi.attr("title"); 118 itemsWidth = itemsWidth - titleLi.outerWidth()-11; 119 titleLi.remove(); 120 removeContent.remove(); 121 showMoreBtn(); 122 if (item.closedHandler != null) 123 item.closedHandler(title); 124 }, 125 mouseover: function () { 126 $(this).css("background-color", "#8DE2B3"); 127 }, 128 mouseout: function () { 129 $(this).attr("style", ""); 130 } 131 }); 132 } 133 var contentDiv; 134 if (item.exist) {//已经存在的不用再创建内容div 135 contentDiv = $(existItems[index]); 136 } else { 137 contentDiv = $("<div></div>").appendTo(itemContentContainer).css({ "width": itemContentContainer.width() - contentPadding * 2 + "px", "height": itemContentContainer.height() - contentPadding * 2 + "px", "margin": "0px", "padding": contentPadding + "px", "overflow": "auto" }).hide();; 138 } 139 if (item.content != "") {//优先取content 140 if ($.isPlainObject(item.content)) { 141 item.content.remove().appendTo(contentDiv); 142 } else { 143 contentDiv.html(item.content); 144 } 145 } else { 146 //是否有url 远程加载 147 if (item.url != "") { 148 load(contentDiv, item,false); 149 } 150 } 151 if (index == 0) {//默认第一个为激活状态 152 showTitleItem = itemTitleLi; 153 showContentItem = contentDiv; 154 } 155 if (item.actived) { 156 showTitleItem = itemTitleLi; 157 showContentItem = contentDiv; 158 } 159 itemsWidth = itemsWidth + itemTitleLi.outerWidth()+11; 160 showMoreBtn(); 161 }; 162 function load(target,item,isReload) { 163 if (item.isiframe) { 164 target.css({ "overflow": "hidden", "padding": "0", "width": target.width() + contentPadding * 2 + "px", "height": target.height() + contentPadding * 2 + "px" }); 165 var loading = $("<div class='loading icon-loading'>正在加载......</div>").appendTo(target); 166 var iframe; 167 if (isReload) { 168 iframe = target.children("iframe")[0]; 169 iframe.contentWindow.location.reload(); 170 } else { 171 iframe = $("<iframe title='" + item.title + "' frameborder='0' style='overflow:visible' scrolling='auto' width='100%' height='100%' src='" + item.url + "' ></iframe>").appendTo(target); 172 iframe.load(function () { 173 loading.remove(); 174 if (item.onLoadSuccess != null) 175 item.onLoadSuccess($(this).attr('title'), target); 176 }); 177 } 178 } else { 179 if (item.dataType == "json") { 180 var ajaxopt = { 181 url: item.url, 182 loadingContainer: target, 183 returnParams: true, 184 params: { title: encodeURIComponent(item.title) } 185 }; 186 if (item.onLoadSuccess != null) 187 ajaxopt.okdeal = function (data, extParams) { 188 item.onLoadSuccess(decodeURIComponent(extParams.title), { data: data, target: target }); 189 }; 190 $.myui.ajaxRequest(ajaxopt); 191 } else { 192 var settings = { url: item.url, extParam: item.title }; 193 if (item.onLoadSuccess != null) 194 settings.loaded = function (t, extParam) { 195 item.onLoadSuccess(extParam, t); 196 }; 197 $.myui.objectLoadContect({ 198 target: target, 199 settings: settings 200 }); 201 } 202 } 203 }; 204 function showMoreBtn() { 205 if (itemsWidth > headerWith) { 206 itemTitleContainer.css("padding-left","9px"); 207 if (leftMoreBtn == null) { 208 var headerWrap = itemTitleContainer.parent("div").parent("div"); 209 leftMoreBtn = $("<a class='leftMoreBtn'></a>").appendTo(headerWrap); 210 rightMoreBtn = $("<a class='rightMoreBtn'></a>").appendTo(headerWrap); 211 leftMoreBtn.bind('click', function () { 212 var position = itemTitleContainer.position(); 213 if (position.left < 9) { 214 var pos = position.left +80; 215 itemTitleContainer.animate({ left: pos },500); 216 } 217 }); 218 rightMoreBtn.bind('click', function () { 219 var position = itemTitleContainer.position(); 220 var pos = position.left -80; 221 itemTitleContainer.animate({ left: pos},500); 222 }); 223 } else { 224 leftMoreBtn.show(); 225 rightMoreBtn.show(); 226 } 227 var diff = itemsWidth - headerWith; 228 itemTitleContainer.animate({ left: -diff }, 500); 229 } else { 230 if (leftMoreBtn != null) { 231 itemTitleContainer.css("padding-left", "0px"); 232 leftMoreBtn.hide(); 233 rightMoreBtn.hide(); 234 var position = itemTitleContainer.position(); 235 if (position.left < 0) { 236 itemTitleContainer.animate({ left: 0 }, 500); 237 } 238 } 239 } 240 } 241 /**********私有方法结束*******************/ 242 /***************************************************************************** 243 *对外的函数统一封装到methods中 244 *调用方式:$.pluginInstance.pluginName("methodName",params) 245 ******************************************************************************/ 246 var methods = { 247 init: function (options) { 248 return this.each(function () { 249 var $this = $(this); 250 var settings 251 if (typeof options == 'undefined') 252 settings = $.fn.tabs.defaults; 253 else 254 settings = $.extend({}, $.fn.tabs.defaults, options); 255 var newItemArr = []; 256 existItems = $this.children("div");//已经存在的item项 257 if (existItems.length > 0) { 258 $.each(existItems, function (i, it) { 259 var $it = $(it); 260 newItemArr.push({ 261 title: $it.attr("title"), 262 content: '', 263 contextMenu: false, 264 closable: $it.attr("closable") == "true" ? true : false, 265 iconcls: $it.attr("iconcls") == undefined ? "" : $it.attr("iconcls"), 266 actived: $it.attr("actived") == "true" ? true : false,// 激活状态 267 isiframe: $it.attr("isiframe") == "true" ? true : false,//如果不配置采用公用 $.fn.tabs.defaults里的配置 268 url: $it.attr("url") == undefined ? "" : $it.attr("url"),//如果不配置采用公用 $.fn.tabs.defaults里的配置 269 dataType: $it.attr("dataType") == undefined ? "json" : $it.attr("dataType"), //如果不配置采用公用 $.fn.tabs.defaults里的配置 270 exist: true, // 271 onLoadSuccess: settings.onLoadSuccess,//fn(tabtitle,resdata) 272 activedHandler: settings.activedHandler,//fn(tabtitle,context) 273 closedHandler: settings.closedHandler //fn(tabtitle) tab被关闭时触发 274 }); 275 }); 276 } 277 //合并每一个tab项的默认设置 278 $.each(settings.items, function (i, item) { 279 var newIt = $.extend({}, $.fn.tabs.itemdefaults, item); 280 newIt.exist = false; 281 if (typeof newIt.onLoadSuccess!='function') 282 newIt.onLoadSuccess = settings.onLoadSuccess;//fn(tabtitle,resdata) 283 if (typeof newIt.activedHandler != 'function') 284 newIt.activedHandler = settings.activedHandler;//fn(tabtitle,context) 285 if (typeof newIt.closedHandler != 'function') 286 newIt.closedHandler = settings.closedHandler; //fn(tabtitle) tab被关闭时触发 287 newItemArr.push(newIt); 288 }); 289 settings.items = newItemArr; 290 //创建ui布局 291 renderHtml($this, settings); 292 if ($.myui.isDebug) { 293 $.myui.log("jQuery.tabs init finish......"); 294 } 295 $this.data('settings', settings); 296 }); 297 }, 298 destroy: function (options) { 299 return $(this).each(function () { 300 var $this = $(this); 301 $this.removeData('settings'); 302 }); 303 }, 304 /*** 305 *opt={ 306 title: 'tab标题', 307 closable: false, 308 iconcls: '', 309 actived: false,// 激活状态 310 isiframe: false,//如果不配置采用公用 $.fn.tabs.defaults里的配置 311 url: '',//如果不配置采用公用 $.fn.tabs.defaults里的配置 312 content: '',//内容默认为空,如果该属性有值,则优先默认采用这个,即使设置url也不会去远程加载数据,content可以是html对象,也可以是文本 313 dataType: 'json',// //如果不配置采用公用 $.fn.tabs.defaults里的配置 314 contextMenu: false //右键菜单未实现 315 } 316 ***/ 317 addTabs: function (opts) { 318 var newOpt = $.extend({}, $.fn.tabs.itemdefaults, opts); 319 newOpt.actived = true; 320 return $(this).each(function () { 321 var $this = $(this); 322 var settings = $this.data('settings'); 323 if (showContentItem != null) 324 showContentItem.hide(); 325 if (showTitleItem != null) 326 showTitleItem.attr("actived", "false").children("a").removeClass("tabs_selected").css("border-bottom", "1px solid #99BBE8"); 327 itemContentContainer = $this; 328 var index = $this.children("div").length; 329 if (typeof newOpt.onLoadSuccess != 'function') 330 newOpt.onLoadSuccess = settings.onLoadSuccess;//fn(tabtitle,resdata) 331 if (typeof newOpt.activedHandler != 'function') 332 newOpt.activedHandler = settings.activedHandler;//fn(tabtitle,context) 333 if (typeof newOpt.closedHandler != 'function') 334 newOpt.closedHandler = settings.closedHandler; //fn(tabtitle) tab被关闭时触发 335 createTab(newOpt, index); 336 showContentItem.show(); 337 showTitleItem.attr("actived", "true").children("a").addClass("tabs_selected").css("border-bottom", "1px solid #FFFFFF"); 338 }); 339 }, 340 /** 341 * 获取选中的tab,返回值{titleObj:...,contentObj:...} 342 ***/ 343 getSelectedTab: function () { 344 return { titleObj: showTitleItem, contentObj: showContentItem }; 345 }, 346 /*** 347 *重新加载某个tab,以title为标准 348 ****/ 349 reLoadTab: function (title) { 350 var $this = $(this); 351 var titlelis = $this.prev().children(".panel-tilte").children("ul").children(); 352 var forIdx = -1; 353 var url = ''; 354 var isIframe = false; 355 var dataType = "html"; 356 var currShowTitle = null; 357 for (var i = 0, len = titlelis.length; i < len; ++i) { 358 var $li = $(titlelis[i]); 359 if ($li.attr("title") == title && $li.attr("url") != undefined && $li.attr("url")!='') { 360 forIdx = i; 361 url = $li.attr("url"); 362 if ($li.attr("isiframe") != undefined) { 363 isIframe = $li.attr("isiframe") == 'true'; 364 } 365 if ($li.attr("datatype") != undefined) { 366 dataType = $li.attr("datatype"); 367 } 368 currShowTitle = $li; 369 break; 370 } 371 } 372 if (forIdx != -1) { 373 var childs = $this.children(); 374 var updateContent = null; 375 for (var i = 0, len = childs.length; i < len;++i){ 376 if (i == forIdx) { 377 updateContent = $(childs[i]); 378 } 379 } 380 if (updateContent != null) { 381 var opts = $this.data('settings'); 382 var it; 383 for (var j = 0, len = opts.items.length; j < len;++j){ 384 if (forIdx == j) 385 it = opts.items[j]; 386 } 387 if (showTitleItem.attr("title") != title) { 388 showContentItem.hide(); 389 showTitleItem.attr("actived", "false").children("a").removeClass("tabs_selected").css("border-bottom", "1px solid #99BBE8"); 390 showContentItem= updateContent.show(); 391 showTitleItem = currShowTitle.attr("actived", "true"); 392 showTitleItem.children("a").addClass("tabs_selected").css("border-bottom", "1px solid #FFFFFF"); 393 } 394 load(updateContent, it, true); 395 } 396 } 397 return $this; 398 }, 399 /**** 400 * 判断某个tab是否存在 401 ****/ 402 isExist: function (title) { 403 var $this = $(this); 404 var titlelis = $this.prev().children(".panel-tilte").children("ul").children(); 405 var forIdx = -1; 406 for (var i = 0, len = titlelis.length; i < len; ++i) { 407 var $li = $(titlelis[i]); 408 if ($li.attr("title") == title && $li.attr("url") != undefined && $li.attr("url") != '') { 409 forIdx = i; 410 break; 411 } 412 } 413 if (forIdx > -1) 414 return true; 415 else 416 return false; 417 } 418 }; 419 /******************** 420 *组件的构造函数 421 *********************/ 422 $.fn.tabs = function () { 423 var method = arguments[0]; 424 if (methods[method]) { 425 method = methods[method]; 426 arguments = Array.prototype.slice.call(arguments, 1); 427 } else if (typeof (method) == 'object' || !method) { 428 if ($.myui.isDebug) { 429 $.myui.log("jQuery.tabs init....."); 430 } 431 method = methods.init; 432 } else { 433 $.error('Method ' + method + ' does not exist on jQuery.tabs'); 434 return this; 435 } 436 return method.apply(this, arguments); 437 }; 438 /******************** 439 *组件的默认配置值 440 *options={ 441 items: [], //tab项配置,对应$.fn.tabs.itemdefaults 442 isiframe: false,// 是否嵌入iframe,嵌入iframe 需要与url配合使用,即采用url加载远程页面时【dataType=html】才起作用 443 url: '', 444 dataType: 'json',// json/html 远程加载时的数据格式 445 onLoadSuccess: null,//fn(tabtitle,resdata) 446 activedHandler: null,//fn(tabtitle,context) 447 closedHandler: null //fn(tabtitle) tab被关闭时触发 448 } 449 *********************/ 450 $.fn.tabs.defaults = { 451 items: [], //tab项配置,对应$.fn.tabs.itemdefaults 452 isiframe: false,// 是否嵌入iframe,嵌入iframe 需要与url配合使用,即采用url加载远程页面时【dataType=html】才起作用 453 url: '', 454 dataType: 'json',// json/html 远程加载时的数据格式 455 onLoadSuccess: null,//fn(tabtitle,resdata) 456 activedHandler: null,//fn(tabtitle) 457 closedHandler: null //fn(tabtitle) tab被关闭时触发 458 }; 459 /*** 460 *每一个tab项目的默认配置 461 ****/ 462 $.fn.tabs.itemdefaults = { 463 title: 'tab标题', 464 closable: false, 465 iconcls: '', 466 actived: false,// 激活状态 467 isiframe: false,//如果不配置采用公用 $.fn.tabs.defaults里的配置 468 url: '',//如果不配置采用公用 $.fn.tabs.defaults里的配置 469 content: '',//内容默认为空,如果该属性有值,则优先默认采用这个,即使设置url也不会去远程加载数据,content可以是html对象,也可以是文本 470 dataType: 'json',// //如果不配置采用公用 $.fn.tabs.defaults里的配置 471 contextMenu: false //右键菜单未实现 472 } 473 })(jQuery);