parent
8b7fcf1f76
commit
54da777b7c
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -9,6 +9,7 @@ interface BrowserRendererRegistry {
|
|||
[browserRendererId: number]: BrowserRenderer;
|
||||
}
|
||||
const browserRenderers: BrowserRendererRegistry = {};
|
||||
let shouldResetScrollAfterNextBatch = false;
|
||||
|
||||
export function attachRootComponentToLogicalElement(browserRendererId: number, logicalElement: LogicalElement, componentId: number): void {
|
||||
|
||||
|
|
@ -67,4 +68,20 @@ export function renderBatch(browserRendererId: number, batch: RenderBatch): void
|
|||
const eventHandlerId = batch.disposedEventHandlerIdsEntry(disposedEventHandlerIdsValues, i);
|
||||
browserRenderer.disposeEventHandler(eventHandlerId);
|
||||
}
|
||||
|
||||
resetScrollIfNeeded();
|
||||
}
|
||||
|
||||
export function resetScrollAfterNextBatch() {
|
||||
shouldResetScrollAfterNextBatch = true;
|
||||
}
|
||||
|
||||
function resetScrollIfNeeded() {
|
||||
if (shouldResetScrollAfterNextBatch) {
|
||||
shouldResetScrollAfterNextBatch = false;
|
||||
|
||||
// This assumes the scroller is on the window itself. There isn't a general way to know
|
||||
// if some other element is playing the role of the primary scroll region.
|
||||
window.scrollTo && window.scrollTo(0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import '@dotnet/jsinterop';
|
||||
import { resetScrollAfterNextBatch } from '../Rendering/Renderer';
|
||||
|
||||
let hasRegisteredNavigationInterception = false;
|
||||
let hasRegisteredNavigationEventListeners = false;
|
||||
|
|
@ -81,6 +82,13 @@ export function navigateTo(uri: string, forceLoad: boolean) {
|
|||
}
|
||||
|
||||
function performInternalNavigation(absoluteInternalHref: string, interceptedLink: boolean) {
|
||||
// Since this was *not* triggered by a back/forward gesture (that goes through a different
|
||||
// code path starting with a popstate event), we don't want to preserve the current scroll
|
||||
// position, so reset it.
|
||||
// To avoid ugly flickering effects, we don't want to change the scroll position until the
|
||||
// we render the new page. As a best approximation, wait until the next batch.
|
||||
resetScrollAfterNextBatch();
|
||||
|
||||
history.pushState(null, /* ignored title */ '', absoluteInternalHref);
|
||||
notifyLocationChanged(interceptedLink);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,6 +418,40 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
Assert.Equal("Oops, that component wasn't found!", app.FindElement(By.Id("test-info")).Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResetsScrollPositionWhenPerformingInternalNavigation_LinkClick()
|
||||
{
|
||||
SetUrlViaPushState("/LongPage1");
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
Browser.Equal("This is a long page you can scroll.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
BrowserScrollY = 500;
|
||||
Browser.True(() => BrowserScrollY > 300); // Exact position doesn't matter
|
||||
|
||||
app.FindElement(By.LinkText("Long page 2")).Click();
|
||||
Browser.Equal("This is another long page you can scroll.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
Browser.Equal(0, () => BrowserScrollY);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResetsScrollPositionWhenPerformingInternalNavigation_ProgrammaticNavigation()
|
||||
{
|
||||
SetUrlViaPushState("/LongPage1");
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
Browser.Equal("This is a long page you can scroll.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
BrowserScrollY = 500;
|
||||
Browser.True(() => BrowserScrollY > 300); // Exact position doesn't matter
|
||||
|
||||
app.FindElement(By.Id("go-to-longpage2")).Click();
|
||||
Browser.Equal("This is another long page you can scroll.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
Browser.Equal(0, () => BrowserScrollY);
|
||||
}
|
||||
|
||||
private long BrowserScrollY
|
||||
{
|
||||
get => (long)((IJavaScriptExecutor)Browser).ExecuteScript("return window.scrollY");
|
||||
set => ((IJavaScriptExecutor)Browser).ExecuteScript($"window.scrollTo(0, {value})");
|
||||
}
|
||||
|
||||
private string SetUrlViaPushState(string relativeUri)
|
||||
{
|
||||
var pathBaseWithoutHash = ServerPathBase.Split('#')[0];
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
<li><NavLink href="/subdir/Other#blah">Other with hash</NavLink></li>
|
||||
<li><NavLink href="/subdir/WithParameters/Name/Abc">With parameters</NavLink></li>
|
||||
<li><NavLink href="/subdir/WithParameters/Name/Abc/LastName/McDef">With more parameters</NavLink></li>
|
||||
<li><NavLink href="/subdir/LongPage1">Long page 1</NavLink></li>
|
||||
<li><NavLink href="/subdir/LongPage2">Long page 2</NavLink></li>
|
||||
</ul>
|
||||
|
||||
<button id="do-navigation" @onclick=@(x => uriHelper.NavigateTo("Other"))>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
@page "/LongPage1"
|
||||
@inject IUriHelper UriHelper
|
||||
<div id="test-info">This is a long page you can scroll.</div>
|
||||
|
||||
<div style="border: 2px dashed red; margin: 1rem; padding: 1rem; height: 1500px;">
|
||||
Scroll past me to find the links
|
||||
</div>
|
||||
|
||||
<button id="go-to-longpage2" @onclick="@(() => UriHelper.NavigateTo("LongPage2"))">
|
||||
Navigate programmatically to long page 2
|
||||
</button>
|
||||
|
||||
<Links />
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@page "/LongPage2"
|
||||
<div id="test-info">This is another long page you can scroll.</div>
|
||||
|
||||
<div style="border: 2px dashed blue; margin: 1rem; padding: 1rem; height: 1500px;">
|
||||
Scroll past me to find the links
|
||||
</div>
|
||||
|
||||
<Links />
|
||||
Loading…
Reference in New Issue