实时应用程序中基于会话的DOM对象可见性操作



我正在开发一个远程监控应用程序,有一个问题,我想看看我是否能得到一些关于如何最好地解决的想法。

当服务器确定数据库中有新信息要显示给客户端时,它会调用SignalR客户端方法,该方法请求新的部分视图。

在主页上,我有一个简单的JQuery脚本,它可以切换部分视图中包含的表和子行的可见性。

这个问题现在应该很明显了。当AJAX使用新返回的局部视图更新DOM时,局部视图中的对象将返回到其初始默认可见性状态。这是完全可以预料的,但是我希望在连接的客户端会话中保持每个元素的可见性状态。

部分视图中的数据基本保持不变(就正常的实时操作而言,不必担心表和/或行被添加或删除。)

代码:

JQuery控件:(未优化,但有效)

    $("#systemDetails").on("click", "#deviceDetail", function () {
    if ($(this).closest('tr').next().is(':hidden')) {
        $("[id^=child]").hide();
        $("[id^=deviceDetail]").removeClass('glyphicon-minus-sign');
        $("[id^=deviceDetail]").addClass('glyphicon-plus-sign');
        $(this).closest('tr').next().toggle("slow");
        $(this).toggleClass("glyphicon-plus-sign glyphicon-minus-sign");
    }
    else {
        $("[id^=child]").hide();
        $(this).toggleClass("glyphicon-plus-sign glyphicon-minus-sign");
    }
});
$("#systemDetails").on("click", "#categoryToggle", function () {
    $(this).closest('table').next().toggle("slow");
    $(this).toggleClass("glyphicon-plus-sign glyphicon-minus-sign");
});

主视图:

    @model xxxx.Models.SystemModel
@{
    ViewBag.Title = "System Details";
}
<div class="row">
    <div class="col-md-12">
        <div id="systemDetails">
            @Html.Action("GetDetails", "Monitoring", Model.Customer.SONumber)
        </div>
    </div>
</div>
@section Scripts{
    <script src="/Scripts/systemdetails.js"></script>
    <script src="/Scripts/jquery.signalR-2.1.2.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="/signalr/hubs"></script>
    <script type="text/javascript">
    $(function () {
        // Declare a proxy to reference the hub.
        var notifications = $.connection.monitoringHub;
        //debugger;
        // Create a function that the hub can call to broadcast messages.
        notifications.client.updateDetails = function (sonumber) {
            getDetails(sonumber)
        };
        // Start the connection.
        $.connection.hub.start().done(function () {
            //alert("connection started")
            getDetails(@Model.Customer.SONumber.ToString());
        }).fail(function (e) {
            alert(e);
        });
    });
    function getDetails(sonumber) {
        if(sonumber = (@Model.Customer.SONumber.ToString())){
            var tbl = $('#systemDetails');
            $.ajax({
                url: '/Monitoring/GetDetails/@Model.Customer.SONumber.ToString()',
                contentType: 'application/html ; charset:utf-8',
                type: 'GET',
                dataType: 'html',
                cache: false
            }).success(function (result) {
                tbl.empty().append(result);
            }).error(function () {
            });
        }
    }
</script>
}

部分视图的相关示例:(如果有更多代码你想看,请请求)

@foreach (var category in Model.Devices.Select(d => d.Room).Distinct())
{
    <table class="table-borderless">
        <tr>
            <td valign="middle"><i class="glyphicon glyphicon-lg glyphicon-plus-sign" id="categoryToggle"></i></td>
            <td><h2 class="tableheader">@category</h2></td>
            @if (Model.Devices.Where(d => d.Room == category).Any(d => d.Status == "Offline"))
            {
                <td valign="middle"><i class="glyphicon glyphicon-lg glyphicon-warning-sign"></i></td>
                <td><h2 class="tableheader">@(Model.Devices.Where(d => d.Room == category && d.Status == "Offline").Count())</h2></td>
            }
            else
            {
                <td valign="middle"><i class="glyphicon glyphicon-lg glyphicon-ok"></i></td>
            }
        </tr>
    </table>
    <table style="display:none" class="table">
    (...)

这里有两种可能的设计路径:

  1. 切换到仅更新数据,而不更新HTML更改更新页面的方式,以便只更新页面中的数据,而不是替换HTML。这将需要对获取和应用更新的方式进行重组,但将保留页面中的所有HTML元素,因此可见性状态也将保留。要做到这一点,您可能会从服务器请求JSON数据,然后客户端代码将这些数据填充到当前HTML中。这显然比您现在所做的工作更多,但它的优点是保留了所有DOM状态,因为DOM元素不会被替换(除了一些文本节点)。

  2. 保存可见性状态,然后在更新DOM后恢复该状态如果要用新的HTML替换DOM对象,则需要保存原始DOM中的可见性设置,然后在用DOM的新部分替换后,必须将这些早期的可见性设置应用于新的DOM元素。这将需要能够将旧的DOM元素映射到相应的新DOM元素。如果您知道表的行结构保持不变,并且只是显示/隐藏行,那么在替换DOM部分之前,您可以在代码中创建一个隐藏行号数组(例如var hiddenRows = [1,5,6,7,10]),然后放入新的HTML,然后隐藏数组中列出的每一行。

最新更新