Skip to content

Commit d3b4351

Browse files
Refactor ion-vue-router, cleanup
1 parent 787f115 commit d3b4351

File tree

12 files changed

+201
-212
lines changed

12 files changed

+201
-212
lines changed

src/components/ion-vue-router-transitionless.vue

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/components/ion-vue-router.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import Vue, { CreateElement, RenderContext, VNodeData } from 'vue';
2+
3+
type TransitionDone = () => void;
4+
interface Props {
5+
name: string;
6+
animated: boolean;
7+
}
8+
9+
// Component entering the view
10+
let enteringEl: HTMLElement;
11+
12+
export default {
13+
name: 'IonVueRouter',
14+
functional: true,
15+
16+
props: {
17+
// Router view name
18+
name: { default: 'default', type: String },
19+
// Disable transitions
20+
animated: { default: true, type: Boolean },
21+
},
22+
23+
render(h: CreateElement, { parent, props, data, children }: RenderContext) {
24+
if (!parent.$router) {
25+
throw new Error('IonTabs requires an instance of either VueRouter or IonicVueRouter');
26+
}
27+
28+
const ionRouterOutletData: VNodeData = {
29+
...data,
30+
ref: 'ionRouterOutlet',
31+
on: { click: (event: Event) => catchIonicGoBack(parent, event) },
32+
};
33+
const routerViewData: VNodeData = { props: { name: props.name } };
34+
const transitionData: VNodeData = {
35+
props: { css: false, mode: 'in-out' },
36+
on: {
37+
leave: (el: HTMLElement, done: TransitionDone) => {
38+
leave(parent, props as Props, el, done);
39+
},
40+
beforeEnter,
41+
enter,
42+
afterEnter,
43+
beforeLeave,
44+
afterLeave,
45+
enterCancelled,
46+
leaveCancelled,
47+
}
48+
};
49+
50+
return h('ion-router-outlet', ionRouterOutletData, [
51+
h('transition', transitionData, [
52+
h('router-view', routerViewData, children)
53+
])
54+
]);
55+
}
56+
};
57+
58+
function catchIonicGoBack(parent: Vue, event: Event): void {
59+
if (!event.target) return;
60+
61+
// We only care for the event coming from Ionic's back button
62+
const backButton = (event.target as HTMLElement).closest('ion-back-button') as HTMLIonBackButtonElement;
63+
if (!backButton) return;
64+
65+
const $router = parent.$router;
66+
let defaultHref: string;
67+
68+
// Explicitly override router direction to always trigger a back transition
69+
$router.directionOverride = -1;
70+
71+
// If we can go back - do so
72+
if ($router.canGoBack()) {
73+
event.preventDefault();
74+
$router.back();
75+
return;
76+
}
77+
78+
// If there's a default fallback - use it
79+
defaultHref = backButton.defaultHref as string;
80+
if (undefined !== defaultHref) {
81+
event.preventDefault();
82+
$router.push(defaultHref);
83+
}
84+
}
85+
86+
// Transition when we leave the route
87+
function leave(parent: Vue, props: Props, el: HTMLElement, done: TransitionDone) {
88+
const promise = transition(parent, props, el);
89+
90+
// Skip any transition if we don't get back a Promise
91+
if (!promise) {
92+
done();
93+
return;
94+
}
95+
96+
// Perform navigation once the transition was finished
97+
parent.$router.transition = new Promise(resolve => {
98+
promise.then(() => {
99+
resolve();
100+
done();
101+
}).catch(console.error);
102+
});
103+
}
104+
105+
// Trigger the ionic/core transitions
106+
function transition(parent: Vue, props: Props, leavingEl: HTMLElement) {
107+
const ionRouterOutlet = parent.$refs.ionRouterOutlet as HTMLIonRouterOutletElement;
108+
109+
// The Ionic framework didn't load - skip animations
110+
if (typeof ionRouterOutlet.componentOnReady === 'undefined') {
111+
return;
112+
}
113+
114+
// Skip animations if there's no component to navigate to
115+
// or the current and the "to-be-rendered" components are the same
116+
if (!enteringEl || enteringEl === leavingEl) {
117+
return;
118+
}
119+
120+
// Add the proper Ionic classes, important for smooth transitions
121+
enteringEl.classList.add('ion-page', 'ion-page-invisible');
122+
123+
// Commit to the transition as soon as the Ionic Router Outlet is ready
124+
return ionRouterOutlet.componentOnReady().then((el: HTMLIonRouterOutletElement) => {
125+
return el.commit(enteringEl, leavingEl, {
126+
deepWait: true,
127+
duration: !props.animated ? 0 : undefined,
128+
direction: parent.$router.direction === 1 ? 'forward' : 'back',
129+
showGoBack: parent.$router.canGoBack(),
130+
});
131+
}).catch(console.error);
132+
}
133+
134+
// Set the component to be rendered before we render the new route
135+
function beforeEnter(el: HTMLElement) {
136+
enteringEl = el;
137+
}
138+
139+
// Enter the new route
140+
function enter(_el: HTMLElement, done: TransitionDone) {
141+
done();
142+
}
143+
144+
// Vue transition stub functions
145+
function afterEnter(_el: HTMLElement) { /* */ }
146+
function afterLeave(_el: HTMLElement) { /* */ }
147+
function beforeLeave(_el: HTMLElement) { /* */ }
148+
function enterCancelled(_el: HTMLElement) { /* */ }
149+
function leaveCancelled(_el: HTMLElement) { /* */ }

src/components/ion-vue-router.vue

Lines changed: 0 additions & 134 deletions
This file was deleted.

src/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ declare module 'vue-router/types/router' {
66
interface VueRouter {
77
direction: number;
88
directionOverride: number | null;
9+
transition: Promise<void>;
910
canGoBack(): boolean;
1011
}
1112
}

src/ionic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { IonicConfig } from '@ionic/core';
1212
import { appInitialize } from './app-initialize';
1313
import { VueDelegate } from './controllers/vue-delegate';
14-
import IonTabs from './components/navigation/IonTabs';
14+
import IonTabs from './components/navigation/ion-tabs';
1515

1616
export interface Controllers {
1717
actionSheetController: ActionSheetController;

src/mixins/catch-ionic-go-back.ts

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)