mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 09:34:19 +08:00
feat(vue): extend useIonRouter hook for programmatic navigation with animation control (#23499)
resolves #23450
This commit is contained in:
@ -32,6 +32,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
|
|||||||
* [Tabs Config](#tabs-config)
|
* [Tabs Config](#tabs-config)
|
||||||
* [Tabs Router Outlet](#tabs-router-outlet)
|
* [Tabs Router Outlet](#tabs-router-outlet)
|
||||||
* [Overlay Events](#overlay-events)
|
* [Overlay Events](#overlay-events)
|
||||||
|
* [Utility Function Types](#utility-function-types)
|
||||||
- [Browser and Platform Support](#browser-and-platform-support)
|
- [Browser and Platform Support](#browser-and-platform-support)
|
||||||
|
|
||||||
|
|
||||||
@ -309,6 +310,12 @@ This applies to the following components: `ion-action-sheet`, `ion-alert`, `ion-
|
|||||||
</ion-modal>
|
</ion-modal>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Utility Function Types
|
||||||
|
|
||||||
|
- The `IonRouter` type for `useIonRouter` has been renamed to `UseIonRouterResult`.
|
||||||
|
|
||||||
|
- The `IonKeyboardRef` type for `useKeyboard` has been renamed to `UseKeyboardResult`.
|
||||||
|
|
||||||
|
|
||||||
### Browser and Platform Support
|
### Browser and Platform Support
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@ import {
|
|||||||
parseQuery,
|
parseQuery,
|
||||||
Router,
|
Router,
|
||||||
RouteLocationNormalized,
|
RouteLocationNormalized,
|
||||||
NavigationFailure
|
NavigationFailure,
|
||||||
|
RouteLocationRaw
|
||||||
} from 'vue-router';
|
} from 'vue-router';
|
||||||
import { createLocationHistory } from './locationHistory';
|
import { createLocationHistory } from './locationHistory';
|
||||||
import { generateId } from './utils';
|
import { generateId } from './utils';
|
||||||
@ -115,13 +116,8 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleNavigate = (path: string, routerAction?: RouteAction, routerDirection?: RouteDirection, routerAnimation?: AnimationBuilder, tab?: string) => {
|
const handleNavigate = (path: RouteLocationRaw, routerAction?: RouteAction, routerDirection?: RouteDirection, routerAnimation?: AnimationBuilder, tab?: string) => {
|
||||||
incomingRouteParams = {
|
setIncomingRouteParams(routerAction, routerDirection, routerAnimation, tab);
|
||||||
routerAction,
|
|
||||||
routerDirection,
|
|
||||||
routerAnimation,
|
|
||||||
tab
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routerAction === 'push') {
|
if (routerAction === 'push') {
|
||||||
router.push(path);
|
router.push(path);
|
||||||
@ -247,11 +243,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
|
|||||||
const navigate = (navigationOptions: ExternalNavigationOptions) => {
|
const navigate = (navigationOptions: ExternalNavigationOptions) => {
|
||||||
const { routerAnimation, routerDirection, routerLink } = navigationOptions;
|
const { routerAnimation, routerDirection, routerLink } = navigationOptions;
|
||||||
|
|
||||||
incomingRouteParams = {
|
setIncomingRouteParams('push', routerDirection, routerAnimation);
|
||||||
routerAnimation,
|
|
||||||
routerDirection: routerDirection || 'forward',
|
|
||||||
routerAction: 'push'
|
|
||||||
}
|
|
||||||
|
|
||||||
router.push(routerLink);
|
router.push(routerLink);
|
||||||
}
|
}
|
||||||
@ -313,7 +305,26 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
|
|||||||
historyChangeListeners.push(cb);
|
historyChangeListeners.push(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setIncomingRouteParams = (routerAction: RouteAction = 'push', routerDirection: RouteDirection = 'forward', routerAnimation?: AnimationBuilder, tab?: string) => {
|
||||||
|
incomingRouteParams = {
|
||||||
|
routerAction,
|
||||||
|
routerDirection,
|
||||||
|
routerAnimation,
|
||||||
|
tab
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = (routerAnimation?: AnimationBuilder) => {
|
||||||
|
setIncomingRouteParams('pop', 'back', routerAnimation);
|
||||||
|
router.back()
|
||||||
|
};
|
||||||
|
const goForward = (routerAnimation?: AnimationBuilder) => {
|
||||||
|
setIncomingRouteParams('push', 'forward', routerAnimation);
|
||||||
|
router.forward();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
handleNavigate,
|
||||||
handleNavigateBack,
|
handleNavigateBack,
|
||||||
handleSetCurrentTab,
|
handleSetCurrentTab,
|
||||||
getCurrentRouteInfo,
|
getCurrentRouteInfo,
|
||||||
@ -321,6 +332,8 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
|
|||||||
navigate,
|
navigate,
|
||||||
resetTab,
|
resetTab,
|
||||||
changeTab,
|
changeTab,
|
||||||
registerHistoryChangeListener
|
registerHistoryChangeListener,
|
||||||
|
goBack,
|
||||||
|
goForward
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@ export interface ExternalNavigationOptions {
|
|||||||
routerLink: string;
|
routerLink: string;
|
||||||
routerDirection?: RouteDirection;
|
routerDirection?: RouteDirection;
|
||||||
routerAnimation?: AnimationBuilder;
|
routerAnimation?: AnimationBuilder;
|
||||||
|
routerAction?: RouteAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NavigationInformation {
|
export interface NavigationInformation {
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
import { BackButtonEvent } from '@ionic/core/components';
|
|
||||||
import {
|
|
||||||
inject,
|
|
||||||
ref,
|
|
||||||
Ref,
|
|
||||||
ComponentInternalInstance,
|
|
||||||
getCurrentInstance
|
|
||||||
} from 'vue';
|
|
||||||
import { LifecycleHooks } from './utils';
|
|
||||||
|
|
||||||
type Handler = (processNextHandler: () => void) => Promise<any> | void | null;
|
|
||||||
|
|
||||||
export interface IonRouter {
|
|
||||||
canGoBack: (deep?: number) => boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IonKeyboardRef {
|
|
||||||
isOpen: Ref<boolean>;
|
|
||||||
keyboardHeight: Ref<number>;
|
|
||||||
unregister: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useBackButton = (priority: number, handler: Handler) => {
|
|
||||||
const callback = (ev: BackButtonEvent) => ev.detail.register(priority, handler);
|
|
||||||
const unregister = () => document.removeEventListener('ionBackButton', callback);
|
|
||||||
|
|
||||||
document.addEventListener('ionBackButton', callback);
|
|
||||||
|
|
||||||
return { unregister };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useIonRouter = (): IonRouter => {
|
|
||||||
const { canGoBack } = inject('navManager') as any;
|
|
||||||
|
|
||||||
return {
|
|
||||||
canGoBack
|
|
||||||
} as IonRouter
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useKeyboard = (): IonKeyboardRef => {
|
|
||||||
let isOpen = ref(false);
|
|
||||||
let keyboardHeight = ref(0);
|
|
||||||
|
|
||||||
const showCallback = (ev: CustomEvent) => {
|
|
||||||
isOpen.value = true;
|
|
||||||
keyboardHeight.value = ev.detail.keyboardHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hideCallback = () => {
|
|
||||||
isOpen.value = false;
|
|
||||||
keyboardHeight.value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unregister = () => {
|
|
||||||
if (typeof (window as any) !== 'undefined') {
|
|
||||||
window.removeEventListener('ionKeyboardDidShow', showCallback);
|
|
||||||
window.removeEventListener('ionKeyboardDidHide', hideCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof (window as any) !== 'undefined') {
|
|
||||||
window.addEventListener('ionKeyboardDidShow', showCallback);
|
|
||||||
window.addEventListener('ionKeyboardDidHide', hideCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
isOpen,
|
|
||||||
keyboardHeight,
|
|
||||||
unregister
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an returns a function that
|
|
||||||
* can be used to provide a lifecycle hook.
|
|
||||||
*/
|
|
||||||
const injectHook = (lifecycleType: LifecycleHooks, hook: Function, component: ComponentInternalInstance | null): Function | undefined => {
|
|
||||||
if (component) {
|
|
||||||
|
|
||||||
// Add to public instance so it is accessible to IonRouterOutlet
|
|
||||||
const target = component as any;
|
|
||||||
const hooks = target.proxy[lifecycleType] || (target.proxy[lifecycleType] = []);
|
|
||||||
const wrappedHook = (...args: unknown[]) => {
|
|
||||||
if (target.isUnmounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return args ? hook(...args) : hook();
|
|
||||||
};
|
|
||||||
|
|
||||||
hooks.push(wrappedHook);
|
|
||||||
|
|
||||||
return wrappedHook;
|
|
||||||
} else {
|
|
||||||
console.warn('[@ionic/vue]: Ionic Lifecycle Hooks can only be used during execution of setup().');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const createHook = <T extends Function = () => any>(lifecycle: LifecycleHooks) => {
|
|
||||||
return (hook: T, target: ComponentInternalInstance | null = getCurrentInstance()) => injectHook(lifecycle, hook, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const onIonViewWillEnter = createHook(LifecycleHooks.WillEnter);
|
|
||||||
export const onIonViewDidEnter = createHook(LifecycleHooks.DidEnter);
|
|
||||||
export const onIonViewWillLeave = createHook(LifecycleHooks.WillLeave);
|
|
||||||
export const onIonViewDidLeave = createHook(LifecycleHooks.DidLeave);
|
|
15
packages/vue/src/hooks/back-button.ts
Normal file
15
packages/vue/src/hooks/back-button.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { BackButtonEvent } from '@ionic/core/components';
|
||||||
|
|
||||||
|
type Handler = (processNextHandler: () => void) => Promise<any> | void | null;
|
||||||
|
export interface UseBackButtonResult {
|
||||||
|
unregister: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useBackButton = (priority: number, handler: Handler): UseBackButtonResult => {
|
||||||
|
const callback = (ev: BackButtonEvent) => ev.detail.register(priority, handler);
|
||||||
|
const unregister = () => document.removeEventListener('ionBackButton', callback);
|
||||||
|
|
||||||
|
document.addEventListener('ionBackButton', callback);
|
||||||
|
|
||||||
|
return { unregister };
|
||||||
|
}
|
40
packages/vue/src/hooks/keyboard.ts
Normal file
40
packages/vue/src/hooks/keyboard.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { ref, Ref } from 'vue';
|
||||||
|
|
||||||
|
export interface UseKeyboardResult {
|
||||||
|
isOpen: Ref<boolean>;
|
||||||
|
keyboardHeight: Ref<number>;
|
||||||
|
unregister: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useKeyboard = (): UseKeyboardResult => {
|
||||||
|
let isOpen = ref(false);
|
||||||
|
let keyboardHeight = ref(0);
|
||||||
|
|
||||||
|
const showCallback = (ev: CustomEvent) => {
|
||||||
|
isOpen.value = true;
|
||||||
|
keyboardHeight.value = ev.detail.keyboardHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideCallback = () => {
|
||||||
|
isOpen.value = false;
|
||||||
|
keyboardHeight.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unregister = () => {
|
||||||
|
if (typeof (window as any) !== 'undefined') {
|
||||||
|
window.removeEventListener('ionKeyboardDidShow', showCallback);
|
||||||
|
window.removeEventListener('ionKeyboardDidHide', hideCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof (window as any) !== 'undefined') {
|
||||||
|
window.addEventListener('ionKeyboardDidShow', showCallback);
|
||||||
|
window.addEventListener('ionKeyboardDidHide', hideCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isOpen,
|
||||||
|
keyboardHeight,
|
||||||
|
unregister
|
||||||
|
}
|
||||||
|
}
|
37
packages/vue/src/hooks/lifecycle.ts
Normal file
37
packages/vue/src/hooks/lifecycle.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { LifecycleHooks } from '../utils';
|
||||||
|
import { ComponentInternalInstance, getCurrentInstance } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an returns a function that
|
||||||
|
* can be used to provide a lifecycle hook.
|
||||||
|
*/
|
||||||
|
const injectHook = (lifecycleType: LifecycleHooks, hook: Function, component: ComponentInternalInstance | null): Function | undefined => {
|
||||||
|
if (component) {
|
||||||
|
|
||||||
|
// Add to public instance so it is accessible to IonRouterOutlet
|
||||||
|
const target = component as any;
|
||||||
|
const hooks = target.proxy[lifecycleType] || (target.proxy[lifecycleType] = []);
|
||||||
|
const wrappedHook = (...args: unknown[]) => {
|
||||||
|
if (target.isUnmounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args ? hook(...args) : hook();
|
||||||
|
};
|
||||||
|
|
||||||
|
hooks.push(wrappedHook);
|
||||||
|
|
||||||
|
return wrappedHook;
|
||||||
|
} else {
|
||||||
|
console.warn('[@ionic/vue]: Ionic Lifecycle Hooks can only be used during execution of setup().');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createHook = <T extends Function = () => any>(lifecycle: LifecycleHooks) => {
|
||||||
|
return (hook: T, target: ComponentInternalInstance | null = getCurrentInstance()) => injectHook(lifecycle, hook, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const onIonViewWillEnter = createHook(LifecycleHooks.WillEnter);
|
||||||
|
export const onIonViewDidEnter = createHook(LifecycleHooks.DidEnter);
|
||||||
|
export const onIonViewWillLeave = createHook(LifecycleHooks.WillLeave);
|
||||||
|
export const onIonViewDidLeave = createHook(LifecycleHooks.DidLeave);
|
69
packages/vue/src/hooks/router.ts
Normal file
69
packages/vue/src/hooks/router.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { inject } from 'vue';
|
||||||
|
import { AnimationBuilder } from '../';
|
||||||
|
|
||||||
|
export type RouteAction = 'push' | 'pop' | 'replace';
|
||||||
|
export type RouteDirection = 'forward' | 'back' | 'root' | 'none';
|
||||||
|
|
||||||
|
export interface UseIonRouterResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location parameter is really of type 'RouteLocationRaw'
|
||||||
|
* imported from vue-router, but the @ionic/vue package should
|
||||||
|
* not have a hard dependency on vue-router, so we just use 'any'.
|
||||||
|
*/
|
||||||
|
canGoBack: (deep?: number) => boolean;
|
||||||
|
push: (location: any, routerAnimation?: AnimationBuilder) => void;
|
||||||
|
replace: (location: any, routerAnimation?: AnimationBuilder) => void;
|
||||||
|
back: (routerAnimation?: AnimationBuilder) => void;
|
||||||
|
forward: (routerAnimation?: AnimationBuilder) => void;
|
||||||
|
navigate: (
|
||||||
|
location: any,
|
||||||
|
routerDirection?: RouteDirection,
|
||||||
|
routerAction?: RouteAction,
|
||||||
|
routerAnimation?: AnimationBuilder
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to navigate within Vue Router
|
||||||
|
* while controlling the animation.
|
||||||
|
*/
|
||||||
|
export const useIonRouter = (): UseIonRouterResult => {
|
||||||
|
const { canGoBack, goBack, goForward, handleNavigate } = inject('navManager') as any;
|
||||||
|
|
||||||
|
const navigate = (
|
||||||
|
location: any,
|
||||||
|
routerDirection?: RouteDirection,
|
||||||
|
routerAction?: RouteAction,
|
||||||
|
routerAnimation?: AnimationBuilder
|
||||||
|
) => handleNavigate(location, routerAction, routerDirection, routerAnimation);
|
||||||
|
|
||||||
|
const push = (
|
||||||
|
location: any,
|
||||||
|
routerAnimation?: AnimationBuilder
|
||||||
|
) => navigate(location, 'forward', 'push', routerAnimation);
|
||||||
|
|
||||||
|
const replace = (
|
||||||
|
location: any,
|
||||||
|
routerAnimation?: AnimationBuilder
|
||||||
|
) => navigate(location, 'root', 'replace', routerAnimation);
|
||||||
|
|
||||||
|
const back = (
|
||||||
|
routerAnimation?: AnimationBuilder
|
||||||
|
) => goBack(routerAnimation);
|
||||||
|
|
||||||
|
const forward = (
|
||||||
|
routerAnimation?: AnimationBuilder
|
||||||
|
) => goForward(routerAnimation);
|
||||||
|
|
||||||
|
return {
|
||||||
|
canGoBack,
|
||||||
|
push,
|
||||||
|
replace,
|
||||||
|
back,
|
||||||
|
forward,
|
||||||
|
navigate
|
||||||
|
} as UseIonRouterResult
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -2,6 +2,12 @@ import { addIcons } from 'ionicons';
|
|||||||
import { arrowBackSharp, caretBackSharp, chevronBack, chevronDown, chevronForward, close, closeCircle, closeSharp, menuOutline, menuSharp, reorderThreeOutline, reorderTwoSharp, searchOutline, searchSharp } from 'ionicons/icons';
|
import { arrowBackSharp, caretBackSharp, chevronBack, chevronDown, chevronForward, close, closeCircle, closeSharp, menuOutline, menuSharp, reorderThreeOutline, reorderTwoSharp, searchOutline, searchSharp } from 'ionicons/icons';
|
||||||
|
|
||||||
export * from './proxies';
|
export * from './proxies';
|
||||||
|
|
||||||
|
export { UseBackButtonResult, useBackButton } from './hooks/back-button';
|
||||||
|
export { UseKeyboardResult, useKeyboard } from './hooks/keyboard';
|
||||||
|
export { onIonViewWillEnter, onIonViewDidEnter, onIonViewWillLeave, onIonViewDidLeave } from './hooks/lifecycle';
|
||||||
|
export { UseIonRouterResult, useIonRouter } from './hooks/router';
|
||||||
|
|
||||||
export { IonicVue } from './ionic-vue';
|
export { IonicVue } from './ionic-vue';
|
||||||
|
|
||||||
export { IonBackButton } from './components/IonBackButton';
|
export { IonBackButton } from './components/IonBackButton';
|
||||||
@ -18,18 +24,6 @@ export { IonModal } from './components/IonModal';
|
|||||||
|
|
||||||
export * from './components/Overlays';
|
export * from './components/Overlays';
|
||||||
|
|
||||||
export {
|
|
||||||
IonKeyboardRef,
|
|
||||||
IonRouter,
|
|
||||||
useBackButton,
|
|
||||||
useIonRouter,
|
|
||||||
useKeyboard,
|
|
||||||
onIonViewWillEnter,
|
|
||||||
onIonViewDidEnter,
|
|
||||||
onIonViewWillLeave,
|
|
||||||
onIonViewDidLeave
|
|
||||||
} from './hooks';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
modalController,
|
modalController,
|
||||||
popoverController,
|
popoverController,
|
||||||
|
254
packages/vue/test-app/tests/unit/hooks.spec.ts
Normal file
254
packages/vue/test-app/tests/unit/hooks.spec.ts
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { createRouter, createWebHistory } from '@ionic/vue-router';
|
||||||
|
import { IonicVue, IonApp, IonRouterOutlet, IonPage, useIonRouter, createAnimation } from '@ionic/vue';
|
||||||
|
import { waitForRouter } from './utils';
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
components: { IonApp, IonRouterOutlet },
|
||||||
|
template: '<ion-app><ion-router-outlet /></ion-app>',
|
||||||
|
}
|
||||||
|
|
||||||
|
const BasePage = {
|
||||||
|
template: '<ion-page></ion-page>',
|
||||||
|
components: { IonPage },
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('useIonRouter', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
(HTMLElement.prototype as HTMLIonRouterOutletElement).commit = jest.fn((entering, leaving, opts) => {
|
||||||
|
if (opts && opts.animationBuilder) {
|
||||||
|
opts.animationBuilder(entering, leaving);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should correctly navigate back', async () => {
|
||||||
|
const Page1 = {
|
||||||
|
...BasePage
|
||||||
|
};
|
||||||
|
|
||||||
|
const Page2 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page2',
|
||||||
|
setup() {
|
||||||
|
const ionRouter = useIonRouter();
|
||||||
|
|
||||||
|
return { ionRouter };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Page1 },
|
||||||
|
{ path: '/page2', component: Page2 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/page2');
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
const cmp = wrapper.findComponent(Page2);
|
||||||
|
const vm = cmp.vm as any;
|
||||||
|
const animFn = jest.fn();
|
||||||
|
|
||||||
|
vm.ionRouter.back(animFn);
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
expect(router.currentRoute.value.path).toEqual('/');
|
||||||
|
expect(animFn).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly navigate forward', async () => {
|
||||||
|
const Page1 = {
|
||||||
|
...BasePage
|
||||||
|
};
|
||||||
|
|
||||||
|
const Page2 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page2',
|
||||||
|
setup() {
|
||||||
|
const ionRouter = useIonRouter();
|
||||||
|
|
||||||
|
return { ionRouter };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Page1 },
|
||||||
|
{ path: '/page2', component: Page2 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/page2');
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
const cmp = wrapper.findComponent(Page2);
|
||||||
|
const vm = cmp.vm as any;
|
||||||
|
const animFn = jest.fn();
|
||||||
|
|
||||||
|
vm.ionRouter.back();
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
expect(router.currentRoute.value.path).toEqual('/');
|
||||||
|
|
||||||
|
vm.ionRouter.forward(animFn);
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
expect(router.currentRoute.value.path).toEqual('/page2');
|
||||||
|
expect(animFn).toHaveBeenCalled();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should correctly push a page', async () => {
|
||||||
|
const Page1 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page1',
|
||||||
|
setup() {
|
||||||
|
const ionRouter = useIonRouter();
|
||||||
|
|
||||||
|
return { ionRouter };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Page2 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page2',
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Page1 },
|
||||||
|
{ path: '/page2', component: Page2 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmp = wrapper.findComponent(Page1);
|
||||||
|
const vm = cmp.vm as any;
|
||||||
|
const animFn = jest.fn();
|
||||||
|
|
||||||
|
vm.ionRouter.push('/page2', animFn);
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
expect(router.currentRoute.value.path).toEqual('/page2');
|
||||||
|
expect(animFn).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly replace a page', async () => {
|
||||||
|
const Page1 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page1',
|
||||||
|
setup() {
|
||||||
|
const ionRouter = useIonRouter();
|
||||||
|
|
||||||
|
return { ionRouter };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Page2 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page2',
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Page1 },
|
||||||
|
{ path: '/page2', component: Page2 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmp = wrapper.findComponent(Page1);
|
||||||
|
const vm = cmp.vm as any;
|
||||||
|
const animFn = jest.fn();
|
||||||
|
|
||||||
|
vm.ionRouter.replace('/page2', animFn);
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
expect(router.currentRoute.value.path).toEqual('/page2');
|
||||||
|
expect(animFn).toHaveBeenCalled();
|
||||||
|
|
||||||
|
expect(vm.ionRouter.canGoBack()).toEqual(false);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should correctly navigate', async () => {
|
||||||
|
const Page1 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page1',
|
||||||
|
setup() {
|
||||||
|
const ionRouter = useIonRouter();
|
||||||
|
|
||||||
|
return { ionRouter };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Page2 = {
|
||||||
|
...BasePage,
|
||||||
|
name: 'Page2',
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Page1 },
|
||||||
|
{ path: '/page2', component: Page2 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmp = wrapper.findComponent(Page1);
|
||||||
|
const vm = cmp.vm as any;
|
||||||
|
const animFn = jest.fn();
|
||||||
|
|
||||||
|
vm.ionRouter.navigate('/page2', 'forward', 'push', animFn);
|
||||||
|
await waitForRouter();
|
||||||
|
|
||||||
|
expect(router.currentRoute.value.path).toEqual('/page2');
|
||||||
|
expect(animFn).toHaveBeenCalled();
|
||||||
|
})
|
||||||
|
})
|
Reference in New Issue
Block a user