Skip to content

Commit 2a47b3e

Browse files
committed
feat: implement a FrameRouter
1 parent bce0623 commit 2a47b3e

File tree

2 files changed

+192
-1
lines changed

2 files changed

+192
-1
lines changed

platform/nativescript/runtime/components/frame.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ export default {
106106
if (back || (ios && this.isGoingBack === undefined)) {
107107
frame.goBack(this.isGoingBack ? undefined : entry)
108108

109-
this.$router.history.isGoingBack = undefined
109+
if (this.$router) {
110+
this.$router.history.isGoingBack = undefined
111+
}
110112
return
111113
}
112114

@@ -117,6 +119,7 @@ export default {
117119
// to fire the frame events
118120
const page = entry.create()
119121
page.once('navigatedTo', () => {
122+
this.$emit('navigated', entry)
120123
entry.clearHistory && this.$emit('replace', entry)
121124
!entry.clearHistory && this.$emit('push', entry)
122125
})

samples/app/app-with-ns-router.js

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
const Vue = require('./nativescript-vue')
2+
3+
Vue.config.silent = false
4+
Vue.config.debug = true
5+
6+
const FrameRouter = function install(Vue, options) {
7+
const navigatorLog = (...args) => {
8+
if (options.debug) {
9+
console.log(...args)
10+
}
11+
}
12+
13+
const navigator = new Vue({
14+
data: {
15+
routes: options.routes,
16+
path: '/', // current path
17+
stack: [],
18+
data: null,
19+
20+
pending: false
21+
},
22+
23+
methods: {
24+
_confirmPathChange() {
25+
navigatorLog(` *** NAVIGATOR::_confirmPathChange() ***`)
26+
27+
if (!this.pending) return
28+
29+
this.path = this.pending.path
30+
this.stack = this.pending.stack
31+
this.data = this.pending.data
32+
33+
this.pending = false
34+
},
35+
_setPending(path, clear = false, data) {
36+
navigatorLog(
37+
` *** NAVIGATOR::_setPending(path = ${path}, clear = ${clear}, data = ${data}) ***`
38+
)
39+
40+
let stack = this.stack.slice()
41+
if (clear) {
42+
stack = [path]
43+
} else {
44+
stack.push(path)
45+
}
46+
47+
this.pending = {
48+
path,
49+
stack,
50+
data
51+
}
52+
},
53+
_getMatched(path = this.path) {
54+
navigatorLog(` *** NAVIGATOR::_getMatched(path = ${path}) ***`)
55+
56+
return this.routes.find(route => route.path === path)
57+
},
58+
59+
push(path, data) {
60+
navigatorLog(` *** NAVIGATOR::push(path = ${path}, data = ${data}) ***`)
61+
62+
this._setPending(path, false, data)
63+
const route = this._getMatched(path)
64+
this.$navigateTo(route.component, {
65+
frame: '__navigator_frame__'
66+
})
67+
},
68+
replace(path, data) {
69+
navigatorLog(
70+
` *** NAVIGATOR::replace(path = ${path}, data = ${data}) ***`
71+
)
72+
73+
this._setPending(path, true, data)
74+
const route = this._getMatched(path)
75+
this.$navigateTo(route.component, {
76+
frame: '__navigator_frame__',
77+
clearHistory: true
78+
})
79+
},
80+
back(notify = false) {
81+
navigatorLog(` *** NAVIGATOR::back(notify = ${notify}) ***`)
82+
83+
if (notify) {
84+
this.stack.pop()
85+
this.path = this.stack[this.stack.length - 1] || '/'
86+
} else {
87+
this.$navigateBack({
88+
frame: '__navigator_frame__'
89+
})
90+
}
91+
}
92+
}
93+
})
94+
95+
Vue.mixin({
96+
beforeCreate() {
97+
this._navigator = navigator
98+
}
99+
})
100+
101+
Object.defineProperty(Vue.prototype, '$navigator', {
102+
get() {
103+
return this._navigator
104+
}
105+
})
106+
107+
Vue.component('FrameRouter', {
108+
data() {
109+
return {
110+
rendered: false
111+
}
112+
},
113+
render(h) {
114+
if (!this.rendered) {
115+
this.rendered = h(navigator._getMatched().component)
116+
}
117+
118+
return h(
119+
'Frame',
120+
{
121+
attrs: {
122+
id: '__navigator_frame__',
123+
...this.$attrs,
124+
...this.$props
125+
},
126+
on: {
127+
back() {
128+
navigator.back(true)
129+
},
130+
navigated() {
131+
navigator._confirmPathChange()
132+
},
133+
...this.$listeners
134+
}
135+
},
136+
[this.rendered]
137+
)
138+
}
139+
})
140+
}
141+
142+
const HomePage = {
143+
template: `
144+
<Page>
145+
<ActionBar title="Navigator Demo"/>
146+
<GridLayout>
147+
<ListView for="item in ['one', 'two', 'three']" @itemTap="$navigator.push('/details', { selected: $event.index })">
148+
<v-template>
149+
<Label :text="item" padding="20"/>
150+
</v-template>
151+
</ListView>
152+
</GridLayout>
153+
</Page>
154+
`
155+
}
156+
157+
const DetailsPage = {
158+
template: `
159+
<Page>
160+
<StackLayout>
161+
<Label text="DetailsPage" />
162+
<Label :text="JSON.stringify($navigator.data, null, 2)" textWrap="true" />
163+
<Button @tap="$navigator.push('/details')" text="Go to details" />
164+
<Button @tap="$navigator.replace('/details')" text="Replace to details" />
165+
166+
<Button @tap="$navigator.back()" text="Go back" />
167+
</StackLayout>
168+
</Page>
169+
`
170+
}
171+
172+
Vue.use(FrameRouter, {
173+
routes: [
174+
{ path: '/', component: HomePage },
175+
{ path: '/details', component: DetailsPage }
176+
],
177+
debug: true
178+
})
179+
180+
new Vue({
181+
template: `
182+
<GridLayout rows="*, auto, *">
183+
<FrameRouter :transition="{ name: 'slide', duration: 1000 }" row="0"/>
184+
<label :text="$navigator.$data.path" row="1" />
185+
<label :text="JSON.stringify($navigator.$data.stack, null, 2)" textWrap="true" row="2" />
186+
</GridLayout>
187+
`
188+
}).$start()

0 commit comments

Comments
 (0)