Blazor JsInterop: Div在JS调用时不可用



这个问题涉及一个客户端Blazor组件。组件包含一个div,该div被一个组件变量隐藏(bool打开)。

我需要组件在组件代码文件中显示div后运行一些Javascript(为了调整它在屏幕上的位置),下面的代码应该能更好地解释这一点:

Component.razor

<div id="select-@Id" class="select-component" style="position: relative;">
<div class="option-selected" @onclick="@OnClick" style="border: 1px solid black;">
@if (opened)
{
<div class="options-wrapper" style="position: absolute; top: 30px; left: 0; border:1px solid red; background-color: white; z-index: 100;">
Sample Content
</div>            
}
</div>
</div>  

Component.razor.cs

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace Accounting.Web.Components.Select
{
public partial class Select
{
[Parameter]
public int Id { get; set; } = default!;

[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
[Inject]
public IJSRuntime JSRuntime { get; set; }
private IJSObjectReference jsModule;
public bool opened = false;

public void OnClick()
{
opened = !opened;
if (opened)
{
jsModule.InvokeVoidAsync("adjustPosition", "select-" + Id);                
} 
}
protected override async Task OnInitializedAsync()
{
jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./scripts/test.js");
}        
}
}

. js

export function adjustPosition(node) {
console.log(node);
console.log($("#" + node + " .options-wrapper").length);   // this always 0 
}

问题是,在OnClick事件中显示的div (.options-wrapper)在我调用JS时还不可用,因此JS脚本无法访问它。

我怀疑这可能是通过在JS脚本中添加计时器来解决的,但是我想知道是否有一个不那么黑客的解决方案可用于我上面的问题?

您应该创建一个ElementReference对象并将其传递给jsModule.InvokeVoidAsync.ElementReference对象将包含对div元素的引用

<div @ref="ReferenceToDiv" id="select-@Id" style="background-color: red; width:300px; height: 300px">
</div>
@code
{
ElementReference ReferenceToDiv;
// As you can see, you should call the "adjustPosition" method from the 
// `OnAfterRenderAsync` method to ensure that the div element has been 
// rendered. DO Not Re-render In Vain. That is, do not use
// await Task.Delay(1); to re-render your component
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (opened)
{
await jsModule.InvokeVoidAsync("adjustPosition", ReferenceToDiv);                
} 
}
public void OnClick()
{
opened = !opened;

}
}

. js

export function adjustPosition(element) {
// Should return 300px
console.log($(element.style.width);   
}

您必须等待渲染来更新DOM。

public /* void */ async Task OnClick()
{
opened = !opened;
await Task.Delay(1);  // allow the rendering to happen
if (opened)
{
await jsModule.InvokeVoidAsync("adjustPosition", "select-" + Id);                
} 
}

如果这不起作用,你可以选择用hidden="@(!opened)"隐藏元素,而不是用@if() { }完全删除它


好的,这可能会导致额外的渲染。如果不需要,请使用另一个答案。

最新更新