@using Microsoft.JSInterop @inject IJSRuntime JS
@if (IsVisible || ForceRender) { @ChildContent } else if (PlaceholderContent != null) { @PlaceholderContent } else {
@if (ShowLoadingIndicator) {
Betöltés...
}
}
@code { private ElementReference _containerRef; private DotNetObjectReference? _dotNetRef; private bool _isObserverInitialized; /// /// Content to render when visible /// [Parameter, EditorRequired] public RenderFragment? ChildContent { get; set; } /// /// Optional placeholder content to show before the element becomes visible /// [Parameter] public RenderFragment? PlaceholderContent { get; set; } /// /// Root margin for IntersectionObserver (e.g., "100px" to load 100px before visible) /// [Parameter] public string RootMargin { get; set; } = "50px"; /// /// Threshold for IntersectionObserver (0.0 to 1.0) /// [Parameter] public double Threshold { get; set; } = 0.01; /// /// Minimum height for the placeholder (prevents layout shift) /// [Parameter] public string MinHeight { get; set; } = "100px"; /// /// CSS class for the container /// [Parameter] public string? ContainerCssClass { get; set; } /// /// Inline style for the container /// [Parameter] public string? ContainerStyle { get; set; } /// /// Force render regardless of visibility (useful for disabling lazy loading) /// [Parameter] public bool ForceRender { get; set; } /// /// Show a loading spinner in the placeholder /// [Parameter] public bool ShowLoadingIndicator { get; set; } = true; /// /// Callback when content becomes visible /// [Parameter] public EventCallback OnContentVisible { get; set; } /// /// Gets whether the content is currently visible /// public bool IsVisible { get; private set; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && !ForceRender) { await InitializeObserverAsync(); } } private async Task InitializeObserverAsync() { if (_isObserverInitialized) return; try { _dotNetRef = DotNetObjectReference.Create(this); // Initialize observer and check immediate visibility var isCurrentlyVisible = await JS.InvokeAsync( "lazyContentObserver.observe", _containerRef, _dotNetRef, RootMargin, Threshold); _isObserverInitialized = true; // If already visible, trigger the callback immediately if (isCurrentlyVisible && !IsVisible) { await OnVisibilityChanged(true); } } catch (JSException ex) { Console.WriteLine($"MgLazyLoadContent: Failed to initialize observer: {ex.Message}"); // Fallback: render immediately if JS fails IsVisible = true; await OnContentVisible.InvokeAsync(); StateHasChanged(); } } [JSInvokable] public async Task OnVisibilityChanged(bool isVisible) { if (IsVisible == isVisible) return; IsVisible = isVisible; if (IsVisible) { await OnContentVisible.InvokeAsync(); } StateHasChanged(); } /// /// Manually triggers the OnContentVisible callback if the content is currently visible. /// Useful when the content data changes but visibility hasn't changed. /// public async Task TriggerContentVisibleAsync() { if (IsVisible) { await OnContentVisible.InvokeAsync(); } } public async ValueTask DisposeAsync() { if (_isObserverInitialized) { try { await JS.InvokeVoidAsync("lazyContentObserver.unobserve", _containerRef); } catch { // Ignore errors during disposal } } _dotNetRef?.Dispose(); } }