在我的MVC Razor视图中,我有一个表,其中的行表示层次结构的两个级别。可以单击每一行以通过ajax调用加载partialview内容区域。这很好。
为了拥有一个更紧凑的列表,我现在想把桌子变成一个“轻型可折叠树视图”。仅当单击其标题行时,才应显示第二级中的行。单击另一个标题行时,应折叠/使所有当前子行不可见,并展开新的子集。
我主要是一个代码隐藏的人,并不习惯客户端脚本。我已经尝试了几种方法,但到目前为止还没有成功。我已经阅读了一些建议,但它们都略有不同,并且不能直接应用。这是我目前的尝试:
<table style="width: 100%;">
<tr>
<td style="width: 30%; vertical-align: top;">
<table id="myTableTree" style="width: 100%;">
@foreach (var testSuite in Model.TestSuites)
{
<tr>
<th colspan="2" style="text-align: left;">
@Ajax.ActionLink(testSuite.Description, "GetContent", new { testSuiteId = testSuite.Id }, new AjaxOptions { UpdateTargetId = "subContent" }, new { onClick = "setShowState(" + testSuite.Id + ");" })
</th>
</tr>
foreach (var testCase in testSuite.TestCases)
{
<tr itemprop="@testSuite.Id" style="display: none;">
<td> </td>
<td>
@Ajax.ActionLink(testCase.Description, "GetContent", new { testCaseId = testCase.Id }, new AjaxOptions { UpdateTargetId = "subContent" })
</td>
</tr>
}
}
</table>
</td>
<td style="vertical-align: top;" id="subContent"></td>
</tr>
</table>
<script type="text/javascript">
function setShowState (testSuiteId)
{
var rows = document.getElementById('myTableTree').rows;
for (var i = 0; i < rows.length; i++)
{
var row = rows.item(i);
if (row.attributes['itemprop'] == testSuiteId)
row.style.display = 'block';
else
row.style.display = 'none';
}
};
</script>
如您所见,所有子行最初都设置为display = none。我抓住了一个任意属性来保存每个第二级行的第一级ID。 itemprop似乎和任何一样好。在第一级行,我添加了一个引用javascript函数的onClick调用。 setShowState函数的目的是循环所有行并为行设置适当的可见性。当我检查生成的页面源它看起来像我期望的方式,但不起作用。从不扩展子行。
1)设置初始服务器返回行display = none然后在客户端切换是否可以?
2)是否可以让actionlink触发ajax服务器调用并触发客户端脚本来设置可见性?或者将ajax调用移动到java脚本只进行一次调用会更好吗?
3)使用display = block / none或visibility = visible / collapse进行切换是否更好?它真的会有什么不同吗?
4)使用itemprop存储父ID是否可以?我看到许多人使用类属性来处理类似情况。可以将class属性与纯整数值一起使用吗?
5)以我想要的方式切换行的最快方法是什么?循环所有行太慢了?我将有10-20个标题行,每行包含2-10个子行。
6)整个设计是不是很糟糕?我没有在MVC工具箱中找到树视图控件,因此我决定采用这种方式。我认为这看起来至少和树视图一样好,但也许另一种方法会更好?
7)jQuery会有什么帮助吗?我在布局页面中包含了jQuery库,但我不知道如何使用它。
答案 0 :(得分:1)
在表达详细问题之前,很多次澄清。经过稍微检查后,我意识到我错过了解析属性的语法。这个例子现在完全正常工作:
<table style="width: 100%;">
<tr>
<td style="width: 30%; vertical-align: top;">
<table id="myTableTree" style="width: 100%;">
@foreach (var testSuite in Model.TestSuites)
{
<tr>
<th colspan="2" style="text-align: left; border: 0;">
@Ajax.ActionLink(testSuite.Description, "GetContent", new { testSuiteId = testSuite.Id }, new AjaxOptions { UpdateTargetId = "subContent" }, new { onClick = "setShowState(" + testSuite.Id + ");" })
</th>
</tr>
foreach (var testCase in testSuite.TestCases)
{
<tr data-testSuiteId="@testSuite.Id" style="visibility: collapse;">
<td style="width: 10%; border: 0;"> </td>
<td style="border: 0;">
@Ajax.ActionLink(testCase.Description, "GetContent", new { testCaseId = testCase.Id }, new AjaxOptions { UpdateTargetId = "subContent" })
</td>
</tr>
}
}
</table>
</td>
<td style="vertical-align: top;" id="subContent"></td>
</tr>
</table>
<script type="text/javascript">
// Toggle each section independantly
function setShowState(testSuiteId) {
var rows = document.querySelectorAll('[data-testSuiteId="' + testSuiteId + '"]');
for (var i = 0; i < rows.length; i++) {
var row = rows.item(i);
row.style.visibility = (row.style.visibility == 'visible') ? 'collapse' : 'visible';
}
};
// Alternative algorithm
// Always collapse previous section when a new one is selected
function setShowState2(testSuiteId) {
var rows = document.getElementById('myTableTree').rows;
for (var i = 0; i < rows.length; i++) {
var row = rows.item(i);
if (row.getAttribute('data-testSuiteId') == testSuiteId)
row.style.visibility = 'visible';
else if (row.getAttribute('data-testSuiteId') != null)
row.style.visibility = 'collapse';
}
};
</script>
我建议对我自己的问题给出以下答案:
1)是的,设置属性然后在客户端切换是完全正常的。
2)是的,似乎可以触发一个服务器端操作并同时触发一个客户端。
3)我试过了。在我的情况下,它似乎同样适用于:显示和可见性。从进一步阅读中我了解到大多数情况下都会使用显示,但表中的可见性略好一些,因为不需要重新计算大小等表格属性。
4)itemprop属性有效。但在HTML5中,建议使用data属性。所以我用“data-testSuiteId”交换了“itemprop”。
5)可能有更快的方法,但这对我来说是可以接受的。
6)替代控制?
7)使用jQuery可以实现同样的目的。这将使代码更紧凑,实际上也更快。
// Toggle section
function setShowState(testSuiteId) {
$("[data-testSuiteId='" + testSuiteId + "']").toggle();
};
// Display one section and collapse all others
function setShowState(testSuiteId) {
$("[data-testSuiteId]").hide();
$("[data-testSuiteId='" + testSuiteId + "']").show();
};