我发现对于“选项卡”设计模式,人们通常希望有一种方法可以链接到特定的选项卡。例如,您可以向某人提供一个 URL,该 URL 会将他们引导至该页面,并激活所需的特定选项卡,并显示正确的内容。
如果每个选项卡都是一个完全不同的 URL,则很容易。在提供的 HTML 中,将相应的类名应用于选项卡以使其看起来处于活动状态,并在下方提供相应的内容。

如果这些选项卡是“同一页面”选项卡,可以即时(或通过 Ajax)隐藏/显示不同的内容面板,则会稍微复杂一些。对此的一种常见(我认为是语义化的)方法是使用哈希链接,例如:
http://example.com/#tab-three

使用 CSS3 的 :target 伪类选择器,可以通过 CSS 独自创建功能性 选项卡区域(无需 JavaScript)。但是,如果目标是纯 CSS 选项卡,这更好。
尽管我尝试过使用 CSS 技术,但我认为功能性选项卡区域最好由 JavaScript 来处理。这是功能领域,如果我们遵循传统的关注点分离模型,则应由 JavaScript 处理。
哈希链接还存在其他一些问题
- 当页面加载带有哈希链接或哈希链接发生更改时,浏览器将向下滚动,以便该哈希的 ID 所对应的元素位于页面顶部。很有可能这不是我们想要的。后者很容易使用
preventDefault()来解决。前者几乎不可能干净地处理。 - 更改页面的哈希标签会向浏览器历史记录中添加一个条目,因此按下后退按钮将返回到之前的哈希。也有可能这不是我们想要的。
让我们同时解决这两个问题,并满足能够链接到特定选项卡的需求。这就是我们要做的
- 不使用哈希链接,而是使用 URL 参数(无向下跳转)。
- 使用超酷的
history.replaceState(),这样我们就可以更改 URL 而不影响后退按钮。
我们的 URL 将类似于
http://example.com/?tab=tab-three
与其从头重写基于 JavaScript 的选项卡,不如使用我现有的 Organic Tabs 演示。我们只需要调整插件的极少量内容即可使其工作。我们将添加一个 param 参数,以便人们可以在其中选择他们想要的任何内容。
$.organicTabs.defaultOptions = {
"speed": 300,
"param": "tab"
};
然后在包含所有选项卡更改功能的部分中,我们将添加这一行
// Change window location to add URL params
if (window.history && history.pushState) {
// NOTE: doesn't take into account existing params
history.replaceState("", "", "?" + base.options.param + "=" + listID);
}
棘手的是,我们需要在页面加载时提取 URL 参数并使用 JavaScript 对其进行处理。这意味着我们需要使用服务器端语言,并将其与我们的 JavaScript 混合在一起。这里我将使用 PHP
更新:我们可以完全通过 JavaScript 访问查询字符串,并 轻松解析各个部分。因此,我们将使用以下代码代替以前位于此处的 PHP 代码(由于许多原因,它并不理想)
var queryString = {};
window.location.href.replace(
new RegExp("([^?=&]+)(=([^&]*))?", "g"),
function($0, $1, $2, $3) { queryString[$1] = $3; }
);
if (queryString[base.options.param]) {
var tab = $("a[href='#" + queryString[base.options.param] + "']");
tab
.closest(".nav")
.find("a")
.removeClass("current")
.end()
.next(".list-wrap")
.find("ul")
.hide();
tab.addClass("current");
$("#" + queryString[base.options.param]).show();
};
此代码获取该 URL 参数,并确保突出显示当前选项卡并显示正确的内容。
功能演示
视频
不完整
history.replaceState(以及所有 历史管理内容)的浏览器支持 远非普遍。我在这里使用了一个基本的特性测试,但没有实现任何回退。重要的部分,即选项卡功能,仍然可以正常工作。您可能需要做更多的事情。
我也没有考虑现有的 URL 参数。如果您的页面已经在使用它们,并且您还想使用此功能(例如 ?foo=bar&tab=tab-one),这将变得更加复杂。您可能需要获取整个 URL 参数字符串并将其传递给插件。然后在使用 replaceState() 时将其解析并重新插入现有参数。
嘿,兄弟,你那里有两个“查看演示”链接。
第二个应该是“下载文件”吧。
抱歉,我的英语不好
过去三年一直在读你的文章
干杯 =)
已修复,并隐藏评论,因为现在已不相关。谢谢!
Chris,检查一下 tab 变量
或者创建一个新变量
我看不出为什么不能从 javascript 获取 url 参数的初始值,而不是使用 php。尤其是在外部 js 文件中 ;)
我前几天偶然发现了这段代码片段,它可能可以用:http://stevenbenner.com/2010/03/javascript-regex-trick-parse-a-query-string-into-an-object/
也许您可以考虑让选项卡插件在初始化时执行这些操作,并且 url 查询可能如下所示
?tabId=tab-1&tabIdTwo=tab-2
其中 tabId 和 tabIdTwo 是运行选项卡插件的元素的 #id?这样,您就可以在一个页面上有多个选项卡控件,并且 url 功能仍然可以工作 :) 只是一个想法 ;)
旁注:请尝试始终编写安全的代码,即使它只是一个概念证明。人们会复制粘贴您的代码而不理解安全隐患。(Anton,您的代码也是如此。)
试试这个
这里有一些 xss 供你参考
另一个不为此使用 php 的理由,当 js 就可以了 :)
仅当选项卡的内容是使用 ajax 加载的,并且您希望在加载时从代码中显示选定选项卡的内容以用于 SEO 目的时,才需要为此使用服务器端脚本。但是选项卡本身的选择仍然可以在 js 中完成。
Jeppe,我同意。
关于 XSS,纯 PHP 确实是一场噩梦。当然,使用 Javascript 也可能搞砸事情。 :)
我删除了所有 PHP 代码,并将其改为纯 JavaScript。感谢 Jeppe 提供的用于轻松获取查询字符串的优秀函数。
当然,仅仅使用 Javascript 而不是 PHP(或其他服务器端技术)并不能免受 XSS 问题的困扰。我认为,如果此示例仅使用一个月前的 jQuery 1.6.2 版本,则它可能会受到 类似攻击 的影响。
我喜欢您用于后退按钮的想法,即
history.replaceState();的想法。我以前不知道这个。但是,我认为从用户体验的角度来看,使用哈希链接(链接中的片段标识符)并不是一个坏主意。Stack Overflow 在很多地方都使用了这种技术,而且我几乎没有在任何地方看到过关于它的抱怨。我将在 Stack Exchange 网络的用户体验部分询问有关此问题的问题。
谢谢。
在 Google+ 中,选项卡几乎可以即时加载(就像它们是同一页面的一部分),但是当我点击其他选项卡时,URL 会立即更改为另一个选项卡,并且不涉及参数。
示例
我位于 plus.google.com/103982534066/about
然后,我点击“图片”按钮。
然后 URL 会立即更改为 plus.google.com/103982534066/pictures,并且可以看到一些图片(选项卡会立即“激活”)。
而且我没有 400 Gbps 的连接。
这是怎么做到的?
通常情况下,我只需使用 jquery 并执行 addClass // removeClass 函数,至少在我的工作中是这样,开发人员讨厌 php,哈哈。
不确定我是否应该以其他方式进行操作,或者是否有任何理由让我以不同的方式操作。
但是,那些不支持
history.replaceState()的其他浏览器呢?我喜欢你一遍又一遍地重新审视主题的方式。这也是我的学习方式,我真的很感谢你的过程。
你提到哈希解决方案的一个问题是浏览器会向下滚动,以便该 ID 对应的元素位于页面顶部。我发现如果我使用 shebang #!,它可以防止滚动,第二个好处是它为 Google 友好的 ajax 选项卡提供了基础。
您可以使用一个*不是*选项卡 ID 的哈希链接。例如,您只需在包装元素(如
tab-list)上放置一个 ID,然后对第三个选项卡使用#tab-list-3的哈希链接。或者可以使用data-属性?选项卡工作得非常好,很棒的工作!
使用 Javascript 将查询字符串放入页面仍然会使页面容易受到下面文档中列出的自引用 iframe XSS 攻击。也就是说,这个问题必须在浏览器级别解决,而不是在站点级别。
https://sitewat.ch/files/Bypassing%20Internet%20Explorer's%20XSS%20Filter.pdf
再次感谢这个很棒的教程。
但我认为有必要提及所有当前的 IE 都不支持
history.replaceState(),因此对于专业网站来说,此解决方案的意义有限。IE10 将支持此功能……但是如果我考虑到有多少用户仍然使用 IE7 浏览我的网站,我将不得不等待另外 10 年才能使用它 :(
我确实提到了这一点。
它在 Opera 浏览器中不起作用,那我们该怎么办?
先生,您一定是做错了什么,我使用 Opera 并且它运行良好。
就目前而言,我仍然需要找到此优秀替代方案的良好用途,也许在内部菜单中使用它,但我仍然不知道如何将其提交以供网站使用,
希望听到您关于如何使用此功能的想法..除了教程中给出的选项之外。
那么,使用 history.replaceState(),它会跟踪查看了哪些选项卡吗?我认为 #tag 在 GA 中不会被记录为单独的页面(也许我还没有找到)。因为从数据记录的角度来看,如果您无法跟踪人们查看了哪些选项卡,则选项卡并不好。
我偶然发现了这篇文章。
我最初是在寻找其他东西,这篇文章的信息量很大,所以我访问了您的主页,看看您还在谈论什么。我很高兴发现您关于可链接选项卡的有用信息——目前似乎很少有关于它的文章。
我一直在努力解决的一个问题:形式与功能。 http://www.example.com/#reports 对我来说感觉比“http://www.example.com/?tab=reports”好——尤其是在最终用户的角度来看。
尽管如此,这篇文章和网站总体而言都非常棒。
您可以用文字替换
new RegExp构造函数:/([^?=&]+)(=([^&]*))?/g,在我看来,这比使用构造函数要简洁得多。好东西
我渴望能够仅使用 CSS 完成这一天。
但目前我仍然使用 jQuery……
谢谢,
David
嗨,
我一直在搜索一个好的与选项卡相关的主题,并看到了这个很棒的主题。
首先感谢您创建如此出色且简单的 jQuery 选项卡。
其次我想问一个问题。
抱歉我的无知。
我在一个页面中使用了 2 个选项卡,现在我想在另一个页面中使用 3 个选项卡,但我遇到的问题是 css 中定义的宽度。
在第一个页面(2 个选项卡)中,我使用了 380px 的宽度
在第二个页面(3 个选项卡)中,我想使用 295px 的宽度。
我想使用示例一,但我不确定如何应用它。
请问有人可以帮我解决这个问题吗?
提前致谢。