fix(@vben/layouts): scope hash targets to layout
This commit is contained in:
@@ -116,6 +116,31 @@ describe('useLayoutScroll', () => {
|
|||||||
expect(element.scrollTo).not.toHaveBeenCalled();
|
expect(element.scrollTo).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should ignore matching hash targets outside the layout', async () => {
|
||||||
|
window.history.replaceState({ position: 0 }, '');
|
||||||
|
const hostTarget = document.createElement('div');
|
||||||
|
hostTarget.id = 'section';
|
||||||
|
hostTarget.scrollIntoView = vi.fn();
|
||||||
|
document.body.append(hostTarget);
|
||||||
|
const element = createScrollElement();
|
||||||
|
const layoutTarget = document.createElement('div');
|
||||||
|
layoutTarget.id = 'section';
|
||||||
|
layoutTarget.scrollIntoView = vi.fn();
|
||||||
|
element.append(layoutTarget);
|
||||||
|
const routerMock = createRouterMock();
|
||||||
|
mountLayoutScroll(routerMock.router);
|
||||||
|
const { afterHook } = routerMock.getHooks();
|
||||||
|
|
||||||
|
window.history.replaceState({ position: 1 }, '');
|
||||||
|
await runAfterHook(afterHook, '#section');
|
||||||
|
|
||||||
|
expect(layoutTarget.scrollIntoView).toHaveBeenCalledWith({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'start',
|
||||||
|
});
|
||||||
|
expect(hostTarget.scrollIntoView).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('should restore a saved position on history navigation', async () => {
|
it('should restore a saved position on history navigation', async () => {
|
||||||
window.history.replaceState({ position: 0 }, '');
|
window.history.replaceState({ position: 0 }, '');
|
||||||
const element = createScrollElement();
|
const element = createScrollElement();
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ function getHistoryPosition() {
|
|||||||
return typeof position === 'number' ? position : undefined;
|
return typeof position === 'number' ? position : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHashTarget(hash: string) {
|
function getHashTarget(scrollElement: HTMLElement, hash: string) {
|
||||||
if (typeof document === 'undefined' || !hash.startsWith('#')) {
|
if (!hash.startsWith('#')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = hash.slice(1);
|
const id = hash.slice(1);
|
||||||
try {
|
try {
|
||||||
return document.querySelector<HTMLElement>(
|
return scrollElement.querySelector<HTMLElement>(
|
||||||
`#${CSS.escape(decodeURIComponent(id))}`,
|
`#${CSS.escape(decodeURIComponent(id))}`,
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return document.querySelector<HTMLElement>(`#${CSS.escape(id)}`);
|
return scrollElement.querySelector<HTMLElement>(`#${CSS.escape(id)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ export function useLayoutScroll(router: LayoutScrollRouter = useRouter()) {
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
if (savedPosition === undefined) {
|
if (savedPosition === undefined) {
|
||||||
const hashTarget = getHashTarget(to.hash);
|
const hashTarget = getHashTarget(scrollElement, to.hash);
|
||||||
if (hashTarget) {
|
if (hashTarget) {
|
||||||
hashTarget.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
hashTarget.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user