Skip to content

Commit 3ae384c

Browse files
committed
deactivate current component during v-component transitions
1 parent 4faf16e commit 3ae384c

File tree

3 files changed

+72
-60
lines changed

3 files changed

+72
-60
lines changed

src/api/lifecycle.js

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@ function ready () {
5555
* directives, turn off all the event listeners, etc.
5656
*
5757
* @param {Boolean} remove - whether to remove the DOM node.
58-
* @param {Function} cb
58+
* @param {Boolean} deferCleanup - if true, defer cleanup to
59+
* be called later
5960
* @public
6061
*/
6162

62-
exports.$destroy = function (remove, cb) {
63+
exports.$destroy = function (remove, deferCleanup) {
6364
if (this._isBeingDestroyed) {
6465
return
6566
}
@@ -98,39 +99,36 @@ exports.$destroy = function (remove, cb) {
9899
var self = this
99100
if (remove && this.$el) {
100101
this.$remove(function () {
101-
cleanup(self)
102-
if (cb) cb()
102+
self._cleanup()
103103
})
104-
} else {
105-
cleanup(self)
104+
} else if (!deferCleanup) {
105+
this._cleanup()
106106
}
107107
}
108108

109109
/**
110110
* Clean up to ensure garbage collection.
111111
* This is called after the leave transition if there
112112
* is any.
113-
*
114-
* @param {Vue} vm
115113
*/
116114

117-
function cleanup (vm) {
115+
exports._cleanup = function () {
118116
// remove reference from data ob
119-
vm._data.__ob__.removeVm(vm)
120-
vm._data =
121-
vm._watchers =
122-
vm._userWatchers =
123-
vm._watcherList =
124-
vm.$el =
125-
vm.$parent =
126-
vm.$root =
127-
vm._children =
128-
vm._directives = null
117+
this._data.__ob__.removeVm(this)
118+
this._data =
119+
this._watchers =
120+
this._userWatchers =
121+
this._watcherList =
122+
this.$el =
123+
this.$parent =
124+
this.$root =
125+
this._children =
126+
this._directives = null
129127
// call the last hook...
130-
vm._isDestroyed = true
131-
vm._callHook('destroyed')
128+
this._isDestroyed = true
129+
this._callHook('destroyed')
132130
// turn off all instance listeners.
133-
vm.$off()
131+
this.$off()
134132
}
135133

136134
/**

src/directives/component.js

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -99,28 +99,41 @@ module.exports = {
9999
},
100100

101101
/**
102-
* Teardown the active vm.
103-
* If keep alive, simply remove it; otherwise destroy it.
104-
*
105-
* @param {Boolean} remove
106-
* @param {Function} cb
102+
* Teardown the current child, but defers cleanup so
103+
* that we can separate the destroy and removal steps.
107104
*/
108105

109-
unbuild: function (remove, cb) {
106+
unbuild: function () {
110107
var child = this.childVM
111-
if (!child) {
112-
if (cb) cb()
108+
if (!child || this.keepAlive) {
113109
return
114110
}
115-
if (this.keepAlive) {
116-
if (remove) {
117-
child.$remove(cb)
118-
}
119-
} else {
120-
if (child._parentUnlinkFn) {
121-
child._parentUnlinkFn()
122-
}
123-
child.$destroy(remove, cb)
111+
if (child._parentUnlinkFn) {
112+
child._parentUnlinkFn()
113+
}
114+
// the sole purpose of `deferCleanup` is so that we can
115+
// "deactivate" the vm right now and perform DOM removal
116+
// later.
117+
child.$destroy(false, true)
118+
},
119+
120+
/**
121+
* Remove current destroyed child and manually do
122+
* the cleanup after removal.
123+
*
124+
* @param {Function} cb
125+
*/
126+
127+
removeCurrent: function (cb) {
128+
var child = this.childVM
129+
var keepAlive = this.keepAlive
130+
if (child) {
131+
child.$remove(function () {
132+
if (!keepAlive) child._cleanup()
133+
if (cb) cb()
134+
})
135+
} else if (cb) {
136+
cb()
124137
}
125138
},
126139

@@ -131,18 +144,21 @@ module.exports = {
131144

132145
update: function (value) {
133146
if (!value) {
134-
this.unbuild(true)
147+
// just destroy and remove current
148+
this.unbuild()
149+
this.removeCurrent()
135150
this.childVM = null
136151
} else {
137152
this.resolveCtor(value)
138-
var child = this.build()
153+
this.unbuild()
154+
var newComponent = this.build()
139155
var self = this
140156
if (this.readyEvent) {
141-
child.$once(this.readyEvent, function () {
142-
self.swapTo(child)
157+
newComponent.$once(this.readyEvent, function () {
158+
self.swapTo(newComponent)
143159
})
144160
} else {
145-
this.swapTo(child)
161+
this.swapTo(newComponent)
146162
}
147163
}
148164
},
@@ -151,41 +167,38 @@ module.exports = {
151167
* Actually swap the components, depending on the
152168
* transition mode. Defaults to simultaneous.
153169
*
154-
* @param {Vue} child - target to swap to
170+
* @param {Vue} target
155171
*/
156172

157-
swapTo: function (child) {
173+
swapTo: function (target) {
158174
var self = this
159175
switch (self.transMode) {
160176
case 'in-out':
161-
child.$before(self.ref, function () {
162-
self.unbuild(true)
163-
self.childVM = child
177+
target.$before(self.ref, function () {
178+
self.removeCurrent()
179+
self.childVM = target
164180
})
165181
break
166182
case 'out-in':
167-
self.unbuild(true, function () {
168-
child.$before(self.ref)
169-
self.childVM = child
183+
self.removeCurrent(function () {
184+
target.$before(self.ref)
185+
self.childVM = target
170186
})
171187
break
172188
default:
173-
self.unbuild(true)
174-
child.$before(self.ref)
175-
self.childVM = child
189+
self.removeCurrent()
190+
target.$before(self.ref)
191+
self.childVM = target
176192
}
177193
},
178194

179195
/**
180196
* Unbind.
181-
* Make sure keepAlive is set to false so that the
182-
* instance is always destroyed.
183197
*/
184198

185199
unbind: function () {
186-
this.keepAlive = false
187200
this.unbuild()
188-
// destroy all cached instances
201+
// destroy all keep-alive cached instances
189202
if (this.cache) {
190203
for (var key in this.cache) {
191204
var child = this.cache[key]

test/unit/specs/directives/component_spec.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ if (_.inBrowser) {
219219
vm.view = 'b'
220220
_.nextTick(function () {
221221
expect(el.textContent).toBe('AAA')
222-
vm._children[1].$emit('ok')
222+
// old vm is already removed, this is the new vm
223+
vm._children[0].$emit('ok')
223224
expect(el.textContent).toBe('BBB')
224225
done()
225226
})

0 commit comments

Comments
 (0)