diff --git a/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor b/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor index e74fbfacfa7..102b9a21cee 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor @@ -16,9 +16,11 @@ </div> // add ReconnectorOutlet component -<component type="typeof(ReconnectorOutlet)" param-AutoReconnect="true" render-mode="ServerPrerendered" /> +<ReconnectorOutlet AutoReconnect="true" ReconnectInterval="5000" @@rendermode="new InteractiveServerRenderMode(false)" /> -

组件参数 AutoReconnect 用于控制是否开启网络重连,默认 true 已开启,可以通过 param-AutoReconnect="false" 关闭

+

AutoReconnect 用于控制是否在连接中断后自动检测服务是否恢复。默认 true;检测到服务恢复时,页面会自动重新加载。设置为 false 可关闭此行为。

+ +

ReconnectInterval 用于设置检测间隔,默认 5000 毫秒,最小值为 1000 毫秒。

@((MarkupString)Localizer["Step2"].Value)

@@ -269,3 +271,5 @@ </ReconnectRejectedTemplate> + + diff --git a/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor b/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor index bbec66f16c0..c8591c0fec7 100644 --- a/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor +++ b/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor @@ -1,6 +1,6 @@ @namespace BootstrapBlazor.Components @inherits BootstrapModuleComponentBase -@attribute [BootstrapModuleAutoLoader("Reconnector/ReconnectorContent.razor.js", AutoInvokeDispose = false)] +@attribute [BootstrapModuleAutoLoader("Reconnector/ReconnectorContent.razor.js")]
diff --git a/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.cs b/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.cs index 9b966d50559..7779f1b530e 100644 --- a/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.cs +++ b/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.cs @@ -67,7 +67,7 @@ protected override async Task InvokeInitAsync() { if (AutoReconnect) { - await InvokeVoidAsync("reconnect", Math.Max(1000, ReconnectInterval)); + await InvokeVoidAsync("init", Id, Math.Max(1000, ReconnectInterval)); } } diff --git a/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.js b/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.js index 35607e281e6..e4378ff5cd1 100644 --- a/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.js +++ b/src/BootstrapBlazor/Components/Reconnector/ReconnectorContent.razor.js @@ -1,26 +1,93 @@ -export function reconnect(interval) { - const reconnectHandler = setInterval(async () => { - const com = document.getElementById('components-reconnect-modal') - if (com) { - if (com.classList.length === 0 || com.classList.contains('components-reconnect-hide')) { - return - } - else { - clearInterval(reconnectHandler) - - async function attemptReload() { - try { - await fetch('') - if (reloadHandler) { - clearInterval(reloadHandler) - } - location.reload() - } - catch { } - } - await attemptReload() - const reloadHandler = setInterval(attemptReload, interval) +import EventHandler from "../../modules/event-handler.js" +import Data from "../../modules/data.js" + +export function init(id, interval) { + dispose(id); + + const modal = document.getElementById('components-reconnect-modal'); + if (modal === null) { + return; + } + + let reloadHandler; + let reloadInProgress = false; + let disposed = false; + + const stopReloading = () => { + if (reloadHandler !== undefined) { + clearInterval(reloadHandler); + reloadHandler = undefined; + } + }; + + const attemptReload = async () => { + if (disposed || reloadInProgress) { + return; + } + + try { + const response = await fetch('', { cache: 'no-store' }); + if (!disposed && response.ok) { + reloadInProgress = true; + stopReloading(); + location.reload(); } } - }, interval) + catch { + } + }; + + const startReloading = () => { + if (reloadHandler !== undefined) { + return; + } + + reloadHandler = setInterval(attemptReload, interval); + void attemptReload(); + }; + + const updateReloading = () => { + if (modal.classList.length === 0 || modal.classList.contains('components-reconnect-hide')) { + stopReloading(); + } + else { + startReloading(); + } + }; + + const stateChanged = event => { + if (event.detail?.state === 'hide') { + stopReloading(); + } + else { + startReloading(); + } + }; + + const observer = new MutationObserver(updateReloading); + observer.observe(modal, { attributes: true, attributeFilter: ['class'] }); + EventHandler.on(modal, 'components-reconnect-state-changed.bb.reconnector', stateChanged); + + Data.set(id, { + modal, + observer, + stateChanged, + dispose: () => { + disposed = true; + stopReloading(); + } + }); + updateReloading(); +} + +export function dispose(id) { + const reconnector = Data.get(id); + if (reconnector === null) { + return; + } + + Data.remove(id); + reconnector.observer.disconnect(); + EventHandler.off(reconnector.modal, 'components-reconnect-state-changed.bb.reconnector', reconnector.stateChanged); + reconnector.dispose(); }