Blazor(服务器)中的奇怪行为(html元素消失),可能是Blazor.server.js



在我正在开发的Blazor(服务器(应用程序中看到一些奇怪的行为。这是一项新技术,一开始并不擅长web开发,但我坐在这里。

问题是,由于某种原因,由于没有调试我故意激发的代码,Blazor在我的页面上删除/添加HTML元素,而据我所知,它没有回调服务器的C#代码。它只对3个html选择元素中的1个执行此操作,这些元素在页面上的编码完全相同。这个特殊的select元素似乎在激发我在C#中的过滤逻辑,但就我的一生而言,我无法弄清楚它是如何做到的。即使是这样,它在做什么方面也不完全正确,因为它与我的C#逻辑有关。

正在删除的是下面显示的@foreach中呈现的span/按钮,但仅当单击";状态码";select元素。它只发生在第一次在@foreach中呈现内容的第一次筛选之后。在那之后,更改"状态代码"选择开始更改HTML客户端,但仅针对一个select元素。不是另外两个。请注意,我目前在C#中已经注释掉了ApplyFilter,它只有在单击"搜索"按钮时才会触发。其他2个select元素的行为与预期完全一样,也就是说,在我实际单击"搜索"按钮之前,@foreach不会发生任何事情。

我已经在@foreach块的浏览器开发工具中为子树更改设置了一个断点,我所描述的是该事件中发生的事情和断点。第一个和第三个select元素不会导致子树发生变化,第二个元素会发生变化。子树更改中断表示blazor.server.js正在调用"removeChildElement"。

我目前没有javascript客户端,除了blazor可能正在做的事情。因此,这是纯粹的Blazor服务器端,HTML/C#w/一些Razor风格的脚本来渲染页面。

提前感谢您对如何进一步调试或找出我在这里做错了什么的想法。。。这可能是我写这个应用程序的方式。

<ul class="nav flex-column">
<li class="nav-item px-3">   
<select class="form-control" @onchange="OnChangeFilterSite">
<option value="all" selected>Select Site :</option>
@foreach (string item in RtuServiceData.Sites) {
if (filterSite != null && filterSite == @item) {
<option selected value="@item">@item</option>
}
else {
<option value="@item">@item</option>    
}
}                
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @onchange="OnChangeFilterStatusCode">
<option value="all" selected>RTU Status :</option>
@foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
if (filterStatusCode != null && filterStatusCode == item.Code) {
<option selected value="@item.Code">@item.Description</option>
}
else {
<option value="@item.Code">@item.Description</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @onchange="OnChangeFilterMatchingOption">
<option value="all" selected>Matching Option :</option>
@foreach (string item in RtuServiceData.MatchingOptions) {
if (filterMatchingOption != null && filterMatchingOption == @item) {
<option selected value="@item">@item</option>
}
else {
<option value="@item">@item</option>    
}
}
</select>
</li>
<li class="nav-item px-3">
<label class="text-white"><b>Filter :</b></label>
<input type="text" class="form-control" @onchange="OnChangeFilterName"/>
<br>
<button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
<br><br>       
</li>
<li class="nav-item px-3">
<div style="height: 300px; overflow: auto; padding-right: 15px">
@foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
<span class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
}
</div>
</li>
</ul>   

下面是处理各种@onchange事件的C#代码。

private string filterSite;
public void OnChangeFilterSite(ChangeEventArgs e)
{
filterSite = e.Value.ToString();
//_ApplyFilter();
}
private string filterStatusCode;
public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
filterStatusCode = e.Value.ToString();
//_ApplyFilter();
}        
private string filterMatchingOption;
public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
filterMatchingOption = e.Value.ToString();
//_ApplyFilter();
}    
private string filterName;
public void OnChangeFilterName(ChangeEventArgs e)
{
filterName = e.Value.ToString();
//_ApplyFilter();
}    

绑定@key="是个好主意;一些独特的";循环中的组件和元素。这有助于Blazor了解发生了什么变化。把它放在跨度上,就像它在一个循环中一样

谢谢。刚刚评论掉的网站和匹配选择,相同的行为。首先选择状态代码,然后在选项之间来回切换,不会有任何作用。单击"搜索"按预期进行筛选,然后单击第一次"搜索"。然后,如果我切换回"状态代码"列表中的"全部"项目,所有按钮都将消失。单击其他选项可以正确筛选。这太奇怪了。

修改了下面的代码。。。

<ul class="nav flex-column">
<li class="nav-item px-3">   
<select class="form-control" @bind="@filterSite">
<option value="all" selected>Select Site :</option>
@foreach (string item in RtuServiceData.Sites) {
if (filterSite != null && filterSite == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>    
}
}                
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterStatusCode">
<option value="all" selected>RTU Status :</option>
@foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
if (filterStatusCode != null && filterStatusCode == item.Code) {
<option @key="@item.Code" selected value="@item.Code">@item.Description</option>
}
else {
<option @key="@item.Code" value="@item.Code">@item.Description</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterMatchingOption">
<option value="all" selected>Matching Option :</option>
@foreach (string item in RtuServiceData.MatchingOptions) {
if (filterMatchingOption != null && filterMatchingOption == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>    
}
}
</select>
</li>
<li class="nav-item px-3">
<label class="text-white"><b>Filter :</b></label>
<input type="text" class="form-control" @bind="@filterName"/>
<br>
<button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
<br><br>       
</li>
<li class="nav-item px-3">
<div style="height: 300px; overflow: auto; padding-right: 15px">
@foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
<span @key="@item.Proposed.ID" class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
}
</div>
</li>
</ul>   
private string filterSite;
@* public void OnChangeFilterSite(ChangeEventArgs e)
{
filterSite = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterStatusCode;
@* public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
filterStatusCode = e.Value.ToString();
//_ApplyFilter();
}         *@
private string filterMatchingOption;
@* public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
filterMatchingOption = e.Value.ToString();
//_ApplyFilter();
}     *@
private string filterName;
@* public void OnChangeFilterName(ChangeEventArgs e)
{
filterName = e.Value.ToString();
//_ApplyFilter();
}     *@

对不起,我所说的"按钮"是指HTML最底部的div,它包含使用引导程序btn类进行样式设置的SPAN元素。应用程序侧边栏部分的完整代码。

<div>
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="rtu">
<span class="oi oi-home" aria-hidden="true"></span> RTU
@* &nbsp&nbsp<span class="spinner-border" role="status"></span> *@
</NavLink>           
</li>      
<li class="nav-item px-3">
<NavLink class="nav-link" href="analogs">
<span class="oi oi-list-rich" aria-hidden="true"></span> Analogs
@* &nbsp&nbsp<span class="spinner-border" role="status"></span> *@
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="digitals">
<span class="oi oi-list-rich" aria-hidden="true"></span> Digitals
@* &nbsp&nbsp<span class="spinner-border" role="status"></span> *@
</NavLink>
</li>       
</ul>
<br>
<ul class="nav flex-column">
<li class="nav-item px-3">   
<select class="form-control" @bind="@filterSite">
<option value="all" selected>Select Site :</option>
@foreach (string item in RtuServiceData.Sites) {
if (filterSite != null && filterSite == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>    
}
}                
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterStatusCode">
<option value="all" selected>RTU Status :</option>
@foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
if (filterStatusCode != null && filterStatusCode == item.Code) {
<option @key="@item.Code" selected value="@item.Code">@item.Description</option>
}
else {
<option @key="@item.Code" value="@item.Code">@item.Description</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterMatchingOption">
<option value="all" selected>Matching Option :</option>
@foreach (string item in RtuServiceData.MatchingOptions) {
if (filterMatchingOption != null && filterMatchingOption == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>    
}
}
</select>
</li>
<li class="nav-item px-3">
<label class="text-white"><b>Filter :</b></label>
<input type="text" class="form-control" @bind="@filterName"/>
<br>
<button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
<br><br>       
</li>
<li class="nav-item px-3">
<div style="height: 300px; overflow: auto; padding-right: 15px">
@foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
<span @key="@item.Proposed.ID" class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
}
</div>
</li>
</ul>   

@代码{

private string filterSite;
@* public void OnChangeFilterSite(ChangeEventArgs e)
{
filterSite = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterStatusCode;
@* public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
filterStatusCode = e.Value.ToString();
//_ApplyFilter();
}         *@
private string filterMatchingOption;
@* public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
filterMatchingOption = e.Value.ToString();
//_ApplyFilter();
}     *@
private string filterName;
@* public void OnChangeFilterName(ChangeEventArgs e)
{
filterName = e.Value.ToString();
//_ApplyFilter();
}     *@
protected override async Task OnInitializedAsync()
{
await Task.Run(_Load);
}
protected void _Load() {  
RtuServiceData.RTUs = RtuService._GetRtuList();
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs;
}
private void _ApplyFilter() {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs;  //get the full list from the singleton

//only filter on site when it's one of the values in the list
if (!string.IsNullOrEmpty(filterSite) && RtuServiceData.Sites.Contains(filterSite)) {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.SITE == filterSite).ToList();
}
//only filter on status code when it's one of the values in the list
if (!string.IsNullOrEmpty(filterStatusCode) && RtuServiceData.StatusCodes.Select(x => x.Code).Contains(filterStatusCode)) {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Accepted.ACCEPTED_STATUS == filterStatusCode);
}
//only filter on matching option when it's one of the values in the list
switch (filterMatchingOption) {
case "100% Match":
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT == 100);
break;
case "< 100% Match":
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT > 0 && r.Proposed.MATCH_PERCENT < 100);
break;
case "No Match":
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT == 0);
break;
default: // default: provides the same functionality as checking filterSite and filterStatusCode against legit values above
break; 
}
//only filter on name when it's populated
if (!string.IsNullOrEmpty(filterName)) {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.RTU.ToUpper().StartsWith(filterName.ToUpper()));
}  
}
private void _SetRtu(int id) {
RtuServiceData.SelectedRtu = null;
NavigationManager.NavigateTo("/");
RtuServiceData.SelectedRtu = RtuService._GetRtu(id);
NavigationManager.NavigateTo("rtu");
}

}

最新更新