将事件附加到表格单元格是典型的示例,也是 jQuery 事件处理历史的缩影。
- 原始演示(版本 < jQuery 1.3) - 在每个 <td> 上使用 .hover()
- 实时演示(jQuery 1.3 <= 版本 < jQuery 1.4.2) - 在 <td> 上使用 .live()
- 委托演示(jQuery 1.4.2 <= 版本) - 在 <table> 上使用 .delegate()
典型表格的 HTML
假设此标记。有五列,因此有五个<colgroup>。colgroup 允许我们为整列设置样式,而无需操作单个表格单元格(因为特定列中的表格单元格没有共同的唯一父级)。
<table>
<colgroup></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
CSS
这里没什么特别的,只是我们准备使用一个类名来处理“当前”行和列的实际样式。
.hover { background-color: #eee; }
最好通过 CSS 处理实际的样式信息,而不是直接在 JavaScript 中处理。
你必须保持它们分开
– 后裔
最佳方法:委托
对于 jQuery 1.4.2+,最佳选择将是委托。以下是两秒钟的概述。您将单个事件监听器(高效!)附加到表格本身,指定哪些元素符合条件。如果表格内的任何地方被点击,它会检查该点击是否在指定的元素之一内。如果有匹配项,它会触发该函数。
$("table").delegate('td','mouseover mouseout', function(e) {
// do stuff
});
我们的“执行操作”是在“悬停”时向行和 colgroup 应用一个类名。然而,“悬停”不是一个真正的事件,真正的事件是mouseover和mouseleave。委托将接受一个用空格分隔的事件列表。在函数中,我们可以测试触发了哪种类型的事件并相应地采取行动。
$("table").delegate('td','mouseover mouseleave', function(e) {
if (e.type == 'mouseover') {
$(this).parent().addClass("hover");
$("colgroup").eq($(this).index()).addClass("hover");
}
else {
$(this).parent().removeClass("hover");
$("colgroup").eq($(this).index()).removeClass("hover");
}
});
由于委托正在监控整个表格,因此如果稍后动态添加新的表格行/单元格,它们仍然会使用此代码运行。
仍然有效的方法:Live
在 jQuery 1.3 之后,但在 jQuery 1.4.2 之前,在这种情况下处理事件的最佳方法是 .live()。还记得我们在委托中是如何监控表格本身以查找指定的事件的吗?使用 live,我们监控整个 <body> 以查找这些事件。这具有明显的优势,它允许动态添加新的行/单元格,而无需重新附加事件,但效率低于委托。
但是需要注意的是,如果将整个新表格动态添加到页面中,live 将继续工作,而委托将无法工作,因为新的表格将没有附加到它的委托。
$('td').live('mouseover', function(){
var i = $(this).prevAll('td').length;
$(this).parent().addClass('hover')
$($cols[i]).addClass('hover');
}).live('mouseout', function(){
var i = $(this).prevAll('td').length;
$(this).parent().removeClass('hover');
$($cols[i]).removeClass('hover');
});
旧的且效率低下的方法
在我们能够使用 live 或委托之前,唯一的方法是直接绑定每个表格单元格的事件。jQuery 仍然有一个帮助函数,但这仍然意味着为每个单独的单元格添加一个事件监听器(效率低下!例如,大量的浏览器内存使用量)。更不用说,如果动态添加新的表格行或单元格,它们将不会像它们的同类一样拥有任何附加的事件。
$("td").hover(function() {
// do stuff
}, function() {
// do stuff
});
如果你想看看所有旧的讨厌的东西,它就在这里。
演示和下载
- 原始演示(版本 < jQuery 1.3) - 在每个 <td> 上使用 .hover()
- 实时演示(jQuery 1.3 <= 版本 < jQuery 1.4.2) - 在 <td> 上使用 .live()
- 委托演示(jQuery 1.4.2 <= 版本) - 在 <table> 上使用 .delegate()
表格更复杂吗?
有 colspan 和 rowspan 等等?Gajus Kuizinas 的 Wholly 项目 可能可以帮助您在这种情况下进行突出显示。
简单、高效且优雅。
谢谢。
一如既往;)
Chris 做得好!
一如既往!
我同意,我期待在我的网站上使用它。这应该是我从 css tricks 中获得的另一个很酷的补充。
更新你的很多文章的决定真是太好了。让这个网站成为一个资源库,而不是一个博客。
谢谢,
@Prydie
我完全同意 Andrew 的说法;特别是引入 jQuery 来解决或优化旧问题。考虑周到,谢谢!
有趣的是,在你悬停在 tr 上之后,jQuery 在标记中留下了空的 class=””。我无法看到这有任何问题。它似乎只是 jQuery 没有完全清理。或者这是一种最佳实践?
好奇……
我喜欢后裔的呼喊。
这是个很棒的重写,先生。谢谢。
Chris 做得好,谢谢……
如果你只需要行突出显示,你可以只用 CSS,不需要 jQuery。
tr:hover { background-color: #444; }
[)amien
你可以将 tr:hover 与 jQuery 一起使用,并删除函数中的额外行吗?这会带来很大改进吗?
这种方法可能很简单,但在 ie6 中不起作用,效率非常低,更多信息可以在这里找到
http://code.google.com/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors
Chris,
您是否有任何指标可以显示每种方法比前一种方法的改进程度?
Greg
简单易行,谢谢
优秀的重写。我之前不确定委托和实时事件的优缺点,这篇文章阐明了其中的一些问题。
Damien - 不确定 IE7 是否支持非链接元素的 :hover,但我确定 IE6 不支持。
非常有效的教程,感谢您的帖子。
在每个示例中“测量”使用情况、执行时间等(Firebug 控制台)会很好。
有时“旧的不好”方法使用更少的资源。
例如,在我的一个测试中,使用 jQuery 手风琴初始化大约需要 17 毫秒,而“手动编码”相同的效果仅需 0.2 毫秒。
@Mike Dedmon
这正是 removeClass 做的事情。它删除了 CSS 类。不多不少!
在这种情况下,它是“hover”。
表格?
哇
太棒了
谢谢
Merci :)
很棒的 Chris…
谢谢…
委托很好!
我做错什么了吗?我只看到一个表格,三个演示都没有悬停效果。在 XP Pro 上运行最新的 Firefox。
好吧,很奇怪。在我家的电脑上运行良好。不确定工作电脑上出了什么问题。
还有一个问题。一些用户如何在帖子旁边显示他们的图片?
您的电子邮件地址使用 Gravatar 系统(请参阅 http://www.gravatar.com)。您的图片将在您使用的每个网站上显示。
哦,谢谢 sage。
在 Opera 10.52 中,只有行被高亮显示,而不是列。
很容易责怪 Opera,而且它实际上可能是 Opera,但我只是想提一下。
仍然有趣地看到“委托”在这里的解释方式。jQuery API 编写得很好,但不知何故,我通常需要第三方解释才能真正“理解它”。
是的,回复我自己。;-)
这个行+列表格(对于感兴趣的人来说,这是一个 em 转换图表!)同时执行两者
http://aloestudios.com/tools/emchart/
但是,它使用的是自定义的“纯”JavaScript 库,而不是 jQuery。所以我不确定它作为在 jQuery 文章中在 Opera 中工作的示例有多有用。
不错,想尝试任何动态内容网站……
Chris,
您真是灵感来源。它从不失败……每次我阅读您的文章时,它都与我正在做的事情有关 - 以某种方式。而且总会有一些灯泡亮起来。
您真棒,先生。说真的。
Scott
很酷的东西。
如何在不使用 colgroups 的情况下仍然实现这一点?
非常好
不错的示例。
但我不想在
mouseover
时对第一个th
和最后一个tr
的第一个td
显示背景。有没有解决方案?
Giovanni Crisci 写道