1

在我的 MVC Razor 视图中,我有一个表,其中的行表示层次结构的两个级别。可以单击每一行以通过 ajax 调用加载部分视图内容区域。这工作正常。

为了获得更紧凑的列表,我现在想将表格变成“轻型可折叠树视图”。只有在单击标题行时才能看到第二级中的行。单击另一个标题行时,所有当前子行都应折叠/不可见,并展开新的子行集。

我主要是一个代码隐藏的人,不太习惯客户端脚本。我已经尝试了几种方法,但到目前为止都没有成功。我已经阅读了一些建议,但它们都略有不同,并不直接适用。这是我目前的尝试:

<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>&nbsp;</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)是否可以设置初始服务器返回行显示=无,然后在客户端切换?

2) 是否可以让 actionlink 触发 ajax 服务器调用并触发客户端脚本来设置可见性?或者将ajax调用移动到java脚本只有一个调用会更好吗?

3) 使用 display=block/none 或 visibility=visible/collapse 切换是否更好?实际上会有什么不同吗?

4)使用itemprop存储父id可以吗?我看到很多人在类似的情况下使用类属性。类属性可以与纯整数值一起使用吗?

5) 以我想要的方式切换行的最快方法是什么?循环所有行是否太慢?我将有 10-20 个标题行,每个标题行有 2-10 个子行。

6) 整个设计不好吗?我在 MVC 工具箱中没有找到树视图控件,因此我决定采用这种方式。我认为这看起来至少和树视图一样好,但也许另一种方法会更好?

7) jQuery 会有帮助吗?我在布局页面中包含了 jQuery 库,但我不知道如何使用它。

4

1 回答 1

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;">&nbsp;</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();
};
于 2013-06-15T19:41:15.987 回答