问题描述
当单击头列时,我想展开和折叠表行。我只想展开/折叠位于特定标题下的行 (点击) 。
这是我的表结构:
<table border="0">
<tr>
<td colspan="2">Header</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td colspan="2">Header</td>
</tr>
<tr>
<td>date</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
</table>
关于如何完成这项任务的任何想法。使用 div 这个任务看起来很简单,但是我有我想要操作的表格数据。
我可以想到的一个想法是在每行中使用 css 类来区分每个标题下的行,并且只有在单击标题时才使用 JQuery 来展开/折叠这些行。但是如果我的表有 10-15 个标题,那么很难跟踪 css 类。
请建议一个合适的方式来实现这一点。
最佳解决方案
你可以这样尝试:
给一个类说 header
到标题行,使用 nextUntil 来获取所点击的标题下面的所有行,直到下一个标题。
JS
$('.header').click(function(){
$(this).nextUntil('tr.header').slideToggle(1000);
});
Html
<table border="0">
<tr class="header">
<td colspan="2">Header</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
Demo
另一个例子:
$('.header').click(function(){
$(this).find('span').text(function(_, value){return value=='-'?'+':'-'});
$(this).nextUntil('tr.header').slideToggle(100); // or just use "toggle()"
});
Demo
您也可以使用 promise 在切换完成之后切换跨度图标/文本 in-case 的动画切换。
$('.header').click(function () {
var $this = $(this);
$(this).nextUntil('tr.header').slideToggle(100).promise().done(function () {
$this.find('span').text(function (_, value) {
return value == '-' ? '+' : '-'
});
});
});
或者只是使用一个 css 伪元素来表示扩展/崩溃的符号,并且只是在标题上切换一个类。
CSS: –
.header .sign:after{
content:"+";
display:inline-block;
}
.header.expand .sign:after{
content:"-";
}
JS: –
$(this).toggleClass('expand').nextUntil('tr.header').slideToggle(100);
Demo
次佳解决方案
实现此目的的最简单的方法是在不改变基于 HTML table
的结构的基础上,在包含标题的 tr
元素 (如.header
) 上使用 class-name 来给出:
<table border="0">
<tr class="header">
<td colspan="2">Header</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr class="header">
<td colspan="2">Header</td>
</tr>
<tr>
<td>date</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
</table>
而 jQuery:
// bind a click-handler to the 'tr' elements with the 'header' class-name:
$('tr.header').click(function(){
/* get all the subsequent 'tr' elements until the next 'tr.header',
set the 'display' property to 'none' (if they're visible), to 'table-row'
if they're not: */
$(this).nextUntil('tr.header').css('display', function(i,v){
return this.style.display === 'table-row' ? 'none' : 'table-row';
});
});
在链接的演示中,我使用 CSS 来隐藏没有 header
class-name 的 tr
元素; 在实践中 (尽管用户的 JavaScript 相对稀少,禁用 JavaScript) 我建议使用 JavaScript 添加相关的 class-names,隐藏和显示适当:
// hide all 'tr' elements, then filter them to find...
$('tr').hide().filter(function () {
// only those 'tr' elements that have 'td' elements with a 'colspan' attribute:
return $(this).find('td[colspan]').length;
// add the 'header' class to those found 'tr' elements
}).addClass('header')
// set the display of those elements to 'table-row':
.css('display', 'table-row')
// bind the click-handler (as above)
.click(function () {
$(this).nextUntil('tr.header').css('display', function (i, v) {
return this.style.display === 'table-row' ? 'none' : 'table-row';
});
});
参考文献:
-
addClass()
。 -
click()
。 -
css()
。 -
filter()
。 -
find()
。 -
hide()
。 -
nextUntil()
。
第三种解决方案
我会说使用 data-
属性将标题与其中的元素相匹配。小提琴:http://jsfiddle.net/GbRAZ/1/
HTML 更改的预览:
<tr class="header" id="header1">
<td colspan="2">Header</td>
</tr>
<tr data-for="header1" style="display:none">
<td>data</td>
<td>data</td>
</tr>
<tr data-for="header1" style="display:none">
<td>data</td>
<td>data</td>
</tr>
JS 代码:
$(".header").click(function () {
$("[data-for="+this.id+"]").slideToggle("slow");
});
编辑:但是,它涉及到一些 HTML 更改。所以我不知道如果这是你想要的。一个更好的方式来构建它将使用<th>
或通过更改整个 html 来使用 ul, ol, etc
甚至 div > span
设置。
第四种方案
我喜欢提供的最简单的答案。但是,我并不喜欢坍塌的烦恼。所以我结合了一个这个问题的解决方案:How to Use slideDown (or show) function on a table row?,使它更顺畅的动画,当行向上或向下滑动。它需要将每个 td 的内容包装在一个 div 中。这使它能够平滑地动画地折叠。当行被展开时,它将只替换内容。
所以这里是 html:
<table>
<tr class="header">
<td>CARS</td>
</tr>
<tr class="thing">
<td>car</td>
</tr>
<tr class="thing">
<td>truck</td>
</tr>
<tr class="header">
<td>HOUSES</td>
</tr>
<tr class="thing">
<td>split level</td>
</tr>
<tr class="thing">
<td>trailer</td>
</tr>
这就是 js
$('.header').click(function(){
if($(this).hasClass("collapsed")){
$(this).nextUntil('tr.header')
.find('td')
.parent()
.find('td > div')
.slideDown("fast", function(){
var $set = $(this);
$set.replaceWith($set.contents());
});
$(this).removeClass("collapsed");
} else {
$(this).nextUntil('tr.header')
.find('td')
.wrapInner('<div style="display: block;" />')
.parent()
.find('td > div')
.slideUp("fast");
$(this).addClass("collapsed");
}
});
结帐这个小提琴为例 https://jsfiddle.net/p9mtqhm7/52/
第五种方案
我扩展了一个答案,但是我的功能有点不同。在我的版本中,不同的行形成不同的组。并且”header” 行触发该特定组的折叠/展开。此外,每个单独的子组记住它的状态。它可能听起来有点混乱,你可以使用 jsfiddle 测试驱动器我的版本。希望这段代码段将有助于有人在那里!
HTML
<table border="0">
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td class='group1'>Group 1</td>
<td>data 2</td>
</tr>
<tr class='group1'>
<td>data 3</td>
<td>data 4</td>
</tr>
<tr>
<td class='group2'>Group 2</td>
<td>data 2</td>
</tr>
<tr class='group2'>
<td>data 3</td>
<td>data 4</td>
</tr>
<tr class='group2'>
<td class='sub_group1'>Sub Group 1</td>
<td>data 6</td>
</tr>
<tr class='group2 sub_group1'>
<td>data 7</td>
<td>data 8</td>
</tr>
<tr class='group2 sub_group1'>
<td>data 9</td>
<td>data 10</td>
</tr>
<tr class='group2 sub_group1'>
<td class='sub_sub_group1'>Sub Sub Group 1</td>
<td>data 11</td>
</tr>
<tr class='group2 sub_group1 sub_sub_group1'>
<td>data 12</td>
<td>data 13</td>
</tr>
<tr class='group2 sub_group1 sub_sub_group1'>
<td>data 14</td>
<td>data 15</td>
</tr>
<tr class='group2'>
<td class='sub_group2'>Sub Group 2</td>
<td>data 11</td>
</tr>
<tr class='group2 sub_group2'>
<td>data 12</td>
<td>data 13</td>
</tr>
<tr class='group2 sub_group2'>
<td>data 14</td>
<td>data 15</td>
</tr>
</table>
CSS
table, tr, td, th
{
border: 1px solid black;
border-collapse:collapse;
}
img.button_open{
content:url('http://code.stephenmorley.org/javascript/collapsible-lists/button-open.png');
cursor:pointer;
}
img.button_closed{
content: url('http://code.stephenmorley.org/javascript/collapsible-lists/button-closed.png');
cursor:pointer;
}
JS
function CreateGroup(group_name)
{
// Create Button(Image)
$('td.' + group_name).prepend("<img class='" + group_name + " button_closed'> ");
// Add Padding to Data
$('tr.' + group_name).each(function () {
var first_td = $(this).children('td').first();
var padding_left = parseInt($(first_td).css('padding-left'));
$(first_td).css('padding-left', String(padding_left + 25) + 'px');
});
RestoreGroup(group_name);
// Tie toggle function to the button
$('img.' + group_name).click(function(){
ToggleGroup(group_name);
});
}
function ToggleGroup(group_name)
{
ToggleButton($('img.' + group_name));
RestoreGroup(group_name);
}
function RestoreGroup(group_name)
{
if ($('img.' + group_name).hasClass('button_open'))
{
// Open everything
$('tr.' + group_name).show();
// Close subgroups that been closed
$('tr.' + group_name).find('img.button_closed').each(function () {
sub_group_name = $(this).attr('class').split(/s+/)[0];
//console.log(sub_group_name);
RestoreGroup(sub_group_name);
});
}
if ($('img.' + group_name).hasClass('button_closed'))
{
// Close everything
$('tr.' + group_name).hide();
}
}
function ToggleButton(button)
{
$(button).toggleClass('button_open');
$(button).toggleClass('button_closed');
}
CreateGroup('group1');
CreateGroup('group2');
CreateGroup('sub_group1');
CreateGroup('sub_group2');
CreateGroup('sub_sub_group1');
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。