Skip to content

Commit d13cdf5

Browse files
committed
support keep-alive
1 parent e6dced2 commit d13cdf5

File tree

3 files changed

+62
-21
lines changed

3 files changed

+62
-21
lines changed

example/advanced/app.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<a v-link="{ path: '/about' }">about</a>
2323
<a v-link="{ path: '/user/1234/profile/what' }">user</a>
2424
<a v-link="{ path: '/forbidden' }">forbidden</a>
25-
<router-view class="view" transition="test" transition-mode="out-in"></router-view>
25+
<router-view class="view" transition="test" transition-mode="out-in" keep-alive></router-view>
2626
</div>
2727
</template>
2828

src/directives/view.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,6 @@ export default function (Vue) {
3333
// finally, init by delegating to v-component
3434
componentDef.bind.call(this)
3535

36-
// does not support keep-alive.
37-
/* istanbul ignore if */
38-
if (this.keepAlive) {
39-
this.keepAlive = false
40-
warn('<router-view> does not support keep-alive.')
41-
}
42-
4336
// all we need to do here is registering this view
4437
// in the router. actual component switching will be
4538
// managed by the pipeline.

src/pipeline.js

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export function deactivate (view, transition, next) {
101101
* @param {Function} [cb]
102102
*/
103103

104-
export function activate (view, transition, depth, cb) {
104+
export function activate (view, transition, depth, cb, reuse) {
105105
let handler = transition.activateQueue[depth]
106106
if (!handler) {
107107
// fix 1.0.0-alpha.3 compat
@@ -120,17 +120,61 @@ export function activate (view, transition, depth, cb) {
120120
view.depth = depth
121121
view.activated = false
122122

123-
// unbuild current component. this step also destroys
124-
// and removes all nested child views.
125-
view.unbuild(true)
126-
// build the new component. this will also create the
127-
// direct child view of the current one. it will register
128-
// itself as view.childView.
129-
let component = view.build({
130-
_meta: {
131-
$loadingRouteData: !!(dataHook && !waitForData)
123+
let component
124+
let loading = !!(dataHook && !waitForData)
125+
126+
// "reuse" is a flag passed down when the parent view is
127+
// either reused via keep-alive or as a child of a kept-alive view.
128+
// of course we can only reuse if the current kept-alive instance
129+
// is of the correct type.
130+
reuse = reuse && view.childVM && view.childVM.constructor === Component
131+
132+
if (reuse) {
133+
// just reuse
134+
component = view.childVM
135+
component.$loadingRouteData = loading
136+
} else {
137+
// unbuild current component. this step also destroys
138+
// and removes all nested child views.
139+
view.unbuild(true)
140+
// handle keep-alive.
141+
// if the view has keep-alive, the child vm is not actually
142+
// destroyed - its nested views will still be in router's
143+
// view list. We need to removed these child views and
144+
// cache them on the child vm.
145+
if (view.keepAlive) {
146+
let views = transition.router._views
147+
let i = views.indexOf(view)
148+
if (i > 0) {
149+
transition.router._views = views.slice(i)
150+
if (view.childVM) {
151+
view.childVM._routerViews = views.slice(0, i)
152+
}
153+
}
132154
}
133-
})
155+
156+
// build the new component. this will also create the
157+
// direct child view of the current one. it will register
158+
// itself as view.childView.
159+
component = view.build({
160+
_meta: {
161+
$loadingRouteData: loading
162+
}
163+
})
164+
// handle keep-alive.
165+
// when a kept-alive child vm is restored, we need to
166+
// add its cached child views into the router's view list,
167+
// and also properly update current view's child view.
168+
if (view.keepAlive) {
169+
component.$loadingRouteData = loading
170+
let cachedViews = component._routerViews
171+
if (cachedViews) {
172+
transition.router._views = cachedViews.concat(transition.router._views)
173+
view.childView = cachedViews[cachedViews.length - 1]
174+
component._routerViews = null
175+
}
176+
}
177+
}
134178

135179
// cleanup the component in case the transition is aborted
136180
// before the component is ever inserted.
@@ -162,7 +206,7 @@ export function activate (view, transition, depth, cb) {
162206
view.activated = true
163207
// activate the child view
164208
if (view.childView) {
165-
activate(view.childView, transition, depth + 1)
209+
activate(view.childView, transition, depth + 1, null, reuse || view.keepAlive)
166210
}
167211
if (dataHook && waitForData) {
168212
// wait until data loaded to insert
@@ -172,7 +216,11 @@ export function activate (view, transition, depth, cb) {
172216
if (dataHook) {
173217
loadData(component, transition, dataHook)
174218
}
175-
insert()
219+
if (!reuse) {
220+
insert()
221+
} else {
222+
cb && cb()
223+
}
176224
}
177225
}
178226

0 commit comments

Comments
 (0)