很久以前因为看别人的js选项卡代码从而步入javascript的美丽大门,现在我也小小的写一个小的教程,但愿能帮助道对js困惑的朋友。
一、结构
使用合理的HTML结构是Javascript UI组件优雅的最重要条件之一,这里使用dl、dt、dd构建选项卡结构(js罗浮宫讨论成果,见司徒正美:jquery tabs插件)
以下为引用的内容: <dl class="artTabs"> <dt id="tabs"><a href="#tabContent1" class="select">link1</a> <a href="#tabContent2">link2</a> <a href="#tabContent3">link3</a></dt> <dd id="tabContent1" style="display:block">tabContent1</dd> <dd id="tabContent2">tabContent2</dd> <dd id="tabContent3">tabContent3</dd> </dl> |
选项卡按钮的锚点都指向内容,这样在脚本与样式失效的情况下仍然能够进行基本的跳转。
二、编写核心javascript代码
接下来就是js编写。使用事件代理机制可以更加高效的处理业务,无需循环遍历操作去给每个按钮绑定事件,也能节省内存:
以下为引用的内容: // 参数:选项卡按钮外包裹元素, 按钮选中的样式, 初始化选中的按钮索引值(以0开始) var artTabs = function (bar, className, index) { var gid = function (id) {return document.getElementById(id)}, buttons = bar.getElementsByTagName('a'), selectButton = buttons[index], showContent = gid(selectButton.href.split('#')[1]); bar.onclick = function (event) { event = event || window.event; var target = event.target || event.srcElement; if (target.nodeName.toLowerCase() === 'a') { showContent.style.display = 'none'; showContent = gid(target.href.split('#')[1]); showContent.style.display = 'block'; selectButton.className = ''; selectButton = target; target.className = className; return false; }; }; }; |
是不是很小巧?以上代码压缩后貌似只有351字节:
以下为引用的内容: var artTabs=function(b,c,i,a){var g=function(x){return document.getElementById(x)},s=b.getElementsByTagName('a'),n=s[i],o=g(n.href.split('#')[1]);b.onclick=function(e){e=e||window.e;a=e.target||e.srcElement;if(a.nodeName.toLowerCase()==='a'){o.style.display='none';o=g(a.href.split('#')[1]);o.style.display='block';n.className='';n=a;a.className=c;return false}}} |
调用范例:artTabs(document.getElementById(‘tabs’), ‘select’, 0);
查看演示:artTabs1.html
三、优化接口
是否发现这个刚出炉的选项卡参数有点麻烦?如果要支持鼠标靠近触发怎么办?或者点击选项卡的时候要采用Ajax加载填充内容要如何处理回调函数?
显然我们前面的API设计并不能优雅的处理这些需求,我们改用字面量的方式传入参数,增加一些新接口,如:
以下为引用的内容: var artTabs = function (bar, config) { var gid = function (id) {return document.getElementById(id)}; config = config || {}; var bar = typeof bar === 'string' ? gid(bar) : bar, className = config.className || 'select', callback = config.callback || function () {}, isMouSEOver = config.isMouseover, buttons = bar.getElementsByTagName('a'), selectButton = buttons[ config.index || function () { var ret = 0; for (i = 0; i < buttons.length; i++) { if (buttons[i].className === className) ret = i; }; return ret; }() ], showContent = gid(selectButton.href.split('#')[1]), fn = function (event) { event = event || window.event; var target = event.target || event.srcElement; if (target.nodeName.toLowerCase() === 'a') { showContent.style.display = 'none'; showContent = gid(target.href.split('#')[1]); showContent.style.display = 'block'; selectButton.className = ''; selectButton = target; target.className = className; target.focus(); callback(selectButton, showContent); return false; }; }; if (isMouseover) bar.onmouseover = fn; bar.onclick = fn;// click事件至少能保证手持设备可以使用 }; |
调用范例:artTabs(‘tabs’);
查看演示:artTabs2.html
四、扩展
原生代码执行效率往往会比框架高,当然我们还是可以很简单写几行代码为jQuery献身,成为其插件:
以下为引用的内容: jQuery.fn.artTabs = function (config) { return this.each(function () { artTabs(this, config); }); }; |
调用范例:jQuery(‘.artTabs > dt’).artTabs();
查看演示:artTabs3.html
以上实现了选项卡最基本的功能,如果需要可以连选项卡HTML结构都封装进去、历史记录支持、URL记忆支持、Ajax数据加载支持等……