我正在开发一个远程监控应用程序,有一个问题,我想看看我是否能得到一些关于如何最好地解决的想法。
当服务器确定数据库中有新信息要显示给客户端时,它会调用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">
(...)
这里有两种可能的设计路径:
-
切换到仅更新数据,而不更新HTML更改更新页面的方式,以便只更新页面中的数据,而不是替换HTML。这将需要对获取和应用更新的方式进行重组,但将保留页面中的所有HTML元素,因此可见性状态也将保留。要做到这一点,您可能会从服务器请求JSON数据,然后客户端代码将这些数据填充到当前HTML中。这显然比您现在所做的工作更多,但它的优点是保留了所有DOM状态,因为DOM元素不会被替换(除了一些文本节点)。
-
保存可见性状态,然后在更新DOM后恢复该状态如果要用新的HTML替换DOM对象,则需要保存原始DOM中的可见性设置,然后在用DOM的新部分替换后,必须将这些早期的可见性设置应用于新的DOM元素。这将需要能够将旧的DOM元素映射到相应的新DOM元素。如果您知道表的行结构保持不变,并且只是显示/隐藏行,那么在替换DOM部分之前,您可以在代码中创建一个隐藏行号数组(例如
var hiddenRows = [1,5,6,7,10]
),然后放入新的HTML,然后隐藏数组中列出的每一行。