Skip to content

Commit 85496cf

Browse files
author
Evan You
committed
messy fix for v-if and v-repeat, need more work.
1 parent 15c0752 commit 85496cf

File tree

4 files changed

+85
-37
lines changed

4 files changed

+85
-37
lines changed

src/compiler.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,22 @@ CompilerProto.setupObserver = function () {
217217
// since hooks were merged with child at head,
218218
// we loop reversely.
219219
while (i--) {
220-
register(hook, fns[i])
220+
registerHook(hook, fns[i])
221221
}
222222
} else if (fns) {
223-
register(hook, fns)
223+
registerHook(hook, fns)
224224
}
225225
})
226226

227+
// broadcast attached/detached hooks
228+
observer
229+
.on('hook:attached', function () {
230+
broadcast(1)
231+
})
232+
.on('hook:detached', function () {
233+
broadcast(0)
234+
})
235+
227236
function onGet (key) {
228237
check(key)
229238
DepsParser.catcher.emit('get', bindings[key])
@@ -235,12 +244,27 @@ CompilerProto.setupObserver = function () {
235244
bindings[key].update(val)
236245
}
237246

238-
function register (hook, fn) {
247+
function registerHook (hook, fn) {
239248
observer.on('hook:' + hook, function () {
240249
fn.call(compiler.vm, options)
241250
})
242251
}
243252

253+
function broadcast (event) {
254+
var children = compiler.childCompilers
255+
if (children) {
256+
var child, i = children.length
257+
while (i--) {
258+
child = children[i]
259+
if (child.el.parentNode) {
260+
event = 'hook:' + (event ? 'attached' : 'detached')
261+
child.observer.emit(event)
262+
child.emitter.emit(event)
263+
}
264+
}
265+
}
266+
}
267+
244268
function check (key) {
245269
if (!bindings[key]) {
246270
compiler.createBinding(key)
@@ -625,6 +649,10 @@ CompilerProto.defineMeta = function (key, binding) {
625649
var vm = this.vm,
626650
ob = this.observer,
627651
value = binding.value = vm[key] || this.data[key]
652+
// remove initital meta in data, since the same piece
653+
// of data can be observed by different VMs, each have
654+
// its own associated meta info.
655+
delete this.data[key]
628656
defGetSet(vm, key, {
629657
get: function () {
630658
if (Observer.shouldGet) ob.emit('get', key)

src/directives/if.js

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,35 @@ var config = require('../config'),
44
module.exports = {
55

66
bind: function () {
7-
this.parent = this.el.parentNode
7+
this.parent = this.el.parentNode || this.el.vue_if_parent
88
this.ref = document.createComment(config.prefix + '-if-' + this.key)
9-
this.el.vue_ref = this.ref
9+
if (this.el.vue_if_ref) {
10+
this.parent.insertBefore(this.ref, this.el.vue_if_ref)
11+
}
12+
this.el.vue_if_ref = this.ref
1013
},
1114

1215
update: function (value) {
1316

1417
var el = this.el
1518

16-
if (!this.parent) { // the node was detached when bound
19+
// sometimes we need to create a VM on a detached node,
20+
// e.g. in v-repeat. In that case, store the desired v-if
21+
// state on the node itself so we can deal with it elsewhere.
22+
el.vue_if = !!value
23+
24+
var parent = this.parent,
25+
ref = this.ref,
26+
compiler = this.compiler
27+
28+
if (!parent) {
1729
if (!el.parentNode) {
1830
return
1931
} else {
20-
this.parent = el.parentNode
32+
parent = this.parent = el.parentNode
2133
}
2234
}
2335

24-
// should always have this.parent if we reach here
25-
var parent = this.parent,
26-
ref = this.ref,
27-
compiler = this.compiler
28-
2936
if (!value) {
3037
transition(el, -1, remove, compiler)
3138
} else {
@@ -52,7 +59,7 @@ module.exports = {
5259
},
5360

5461
unbind: function () {
55-
this.el.vue_ref = null
62+
this.el.vue_if_ref = this.el.vue_if_parent = null
5663
var ref = this.ref
5764
if (ref.parentNode) {
5865
ref.parentNode.removeChild(ref)

src/directives/repeat.js

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
var Observer = require('../observer'),
22
utils = require('../utils'),
33
config = require('../config'),
4-
transition = require('../transition'),
54
def = utils.defProtected,
65
ViewModel // lazy def to avoid circular dependency
76

@@ -247,17 +246,19 @@ module.exports = {
247246
var ctn = this.container,
248247
vms = this.vms,
249248
col = this.collection,
250-
el, i, ref, item, primitive, detached
249+
el, i, existing, ref, item, primitive, detached
251250

252251
// append node into DOM first
253252
// so v-if can get access to parentNode
253+
// TODO: logic here is a total mess.
254254
if (data) {
255255

256256
if (this.old) {
257257
i = indexOf(this.old, data)
258258
}
259+
existing = i > -1
259260

260-
if (i > -1) { // existing, reuse the old VM
261+
if (existing) { // existing, reuse the old VM
261262

262263
item = this.oldVMs[i]
263264
// mark, so it won't be destroyed
@@ -285,23 +286,26 @@ module.exports = {
285286
ref = vms.length > index
286287
? vms[index].$el
287288
: this.ref
288-
// make sure it works with v-if
289-
if (!ref.parentNode) ref = ref.vue_ref
290-
if (!detached) {
291-
if (i > -1) {
292-
// no need to transition existing node
293-
ctn.insertBefore(el, ref)
294-
} else {
295-
// insert new node with transition
296-
transition(el, 1, function () {
297-
ctn.insertBefore(el, ref)
298-
}, this.compiler)
299-
}
289+
290+
// if ref VM's el is detached by v-if
291+
// use its v-if ref node instead
292+
if (!ref.parentNode) {
293+
ref = ref.vue_if_ref
294+
}
295+
296+
if (existing) {
297+
// existing node
298+
// if not detached, just re-insert to new location
299+
// else re-insert its v-if ref node
300+
ctn.insertBefore(detached ? el.vue_if_ref : el, ref)
300301
} else {
301-
// detached by v-if
302-
// just move the comment ref node
303-
ctn.insertBefore(el.vue_ref, ref)
302+
// new node, prepare it for v-if
303+
el.vue_if_parent = ctn
304+
el.vue_if_ref = ref
304305
}
306+
// set index so vm can init with it
307+
// and do not trigger stuff early
308+
data.$index = index
305309
}
306310

307311
item = item || new this.Ctor({
@@ -320,6 +324,7 @@ module.exports = {
320324
item.$destroy()
321325
} else {
322326
vms.splice(index, 0, item)
327+
323328
// for primitive values, listen for value change
324329
if (primitive) {
325330
item.$compiler.observer.on('set', function (key, val) {
@@ -328,6 +333,19 @@ module.exports = {
328333
}
329334
})
330335
}
336+
337+
// new instance and v-if doesn't want it detached
338+
// good to insert.
339+
if (!existing && el.vue_if !== false) {
340+
if (this.compiler.init) {
341+
// do not transition on initial compile.
342+
ctn.insertBefore(item.$el, ref)
343+
item.$compiler.execHook('attached')
344+
} else {
345+
// transition in...
346+
item.$before(ref)
347+
}
348+
}
331349
}
332350

333351
return item

src/observer.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,7 @@ function watchArray (arr) {
131131
*/
132132
function convert (obj, key) {
133133
var keyPrefix = key.charAt(0)
134-
if (
135-
(keyPrefix === '$' || keyPrefix === '_') &&
136-
key !== '$index' &&
137-
key !== '$key' &&
138-
key !== '$value'
139-
) {
134+
if (keyPrefix === '$' || keyPrefix === '_') {
140135
return
141136
}
142137
// emit set on bind

0 commit comments

Comments
 (0)