1
1
var _ = require ( '../util' )
2
+ var config = require ( '../config' )
2
3
var isObject = _ . isObject
3
4
var isPlainObject = _ . isPlainObject
4
5
var textParser = require ( '../parsers/text' )
@@ -47,7 +48,8 @@ module.exports = {
47
48
this . idKey =
48
49
this . _checkParam ( 'track-by' ) ||
49
50
this . _checkParam ( 'trackby' ) // 0.11.0 compat
50
- // cache for primitive value instances
51
+ this . hasTransition =
52
+ this . el . hasAttribute ( config . prefix + 'transition' )
51
53
this . cache = Object . create ( null )
52
54
} ,
53
55
@@ -96,7 +98,7 @@ module.exports = {
96
98
this . template = transclude ( this . template )
97
99
this . _linkFn = compile ( this . template , options )
98
100
} else {
99
- this . _asComponent = true
101
+ this . asComponent = true
100
102
var tokens = textParser . parse ( id )
101
103
if ( ! tokens ) { // static component
102
104
var Ctor = this . Ctor = options . components [ id ]
@@ -127,14 +129,27 @@ module.exports = {
127
129
* Update.
128
130
* This is called whenever the Array mutates.
129
131
*
130
- * @param {Array } data
132
+ * @param {Array|Number|String } data
131
133
*/
132
134
133
135
update : function ( data ) {
134
- if ( typeof data === 'number' ) {
136
+ data = data || [ ]
137
+ var type = typeof data
138
+ if ( type === 'number' ) {
135
139
data = range ( data )
140
+ } else if ( type === 'string' ) {
141
+ data = _ . toArray ( data )
136
142
}
137
- this . vms = this . diff ( data || [ ] , this . vms )
143
+ // There are two situations where we have to use the
144
+ // more complex but more accurate diff algorithm:
145
+ // 1. We are using components with v-repeat - the
146
+ // components could have additional state outside
147
+ // of v-repeat data.
148
+ // 2. We have transitions on the list, which requires
149
+ // precise DOM re-positioning.
150
+ this . vms = this . asComponent || this . hasTransition
151
+ ? this . diff ( data , this . vms )
152
+ : this . inplaceUpdate ( data , this . vms )
138
153
// update v-ref
139
154
if ( this . refID ) {
140
155
this . vm . $ [ this . refID ] = this . vms
@@ -146,6 +161,43 @@ module.exports = {
146
161
}
147
162
} ,
148
163
164
+ /**
165
+ * Inplace update that maximally reuses existing vm
166
+ * instances and DOM nodes by simply swapping data into
167
+ * existing vms.
168
+ *
169
+ * @param {Array } data
170
+ * @param {Array } oldVms
171
+ * @return {Array }
172
+ */
173
+
174
+ inplaceUpdate : function ( data , oldVms ) {
175
+ oldVms = oldVms || [ ]
176
+ var vms
177
+ var dir = this
178
+ var alias = dir . arg
179
+ var converted = dir . converted
180
+ if ( data . length < oldVms . length ) {
181
+ oldVms . slice ( data . length ) . forEach ( function ( vm ) {
182
+ vm . $destroy ( true )
183
+ } )
184
+ vms = oldVms . slice ( 0 , data . length )
185
+ overwrite ( data , vms , alias , converted )
186
+ } else if ( data . length > oldVms . length ) {
187
+ var newVms = data . slice ( oldVms . length ) . map ( function ( data , i ) {
188
+ var vm = dir . build ( data , i + oldVms . length )
189
+ vm . $before ( dir . ref )
190
+ return vm
191
+ } )
192
+ overwrite ( data . slice ( 0 , oldVms . length ) , oldVms , alias , converted )
193
+ vms = oldVms . concat ( newVms )
194
+ } else {
195
+ overwrite ( data , oldVms , alias , converted )
196
+ vms = oldVms
197
+ }
198
+ return vms
199
+ } ,
200
+
149
201
/**
150
202
* Diff, based on new data and old data, determine the
151
203
* minimum amount of DOM manipulations needed to make the
@@ -192,7 +244,7 @@ module.exports = {
192
244
}
193
245
}
194
246
} else { // new instance
195
- vm = this . build ( obj , i )
247
+ vm = this . build ( obj , i , true )
196
248
vm . _new = true
197
249
}
198
250
vms [ i ] = vm
@@ -258,9 +310,10 @@ module.exports = {
258
310
*
259
311
* @param {Object } data
260
312
* @param {Number } index
313
+ * @param {Boolean } needCache
261
314
*/
262
315
263
- build : function ( data , index ) {
316
+ build : function ( data , index , needCache ) {
264
317
var original = data
265
318
var meta = { $index : index }
266
319
if ( this . converted ) {
@@ -280,14 +333,19 @@ module.exports = {
280
333
var Ctor = this . Ctor || this . resolveCtor ( data , meta )
281
334
var vm = this . vm . $addChild ( {
282
335
el : templateParser . clone ( this . template ) ,
283
- _asComponent : this . _asComponent ,
336
+ _asComponent : this . asComponent ,
284
337
_linkFn : this . _linkFn ,
285
338
_meta : meta ,
286
339
data : data ,
287
340
inherit : this . inherit
288
341
} , Ctor )
342
+ // flag this instance as a repeat instance
343
+ // so that we can skip it in vm._digest
344
+ vm . _repeat = true
289
345
// cache instance
290
- this . cacheVm ( raw , vm )
346
+ if ( needCache ) {
347
+ this . cacheVm ( raw , vm )
348
+ }
291
349
return vm
292
350
} ,
293
351
@@ -328,12 +386,15 @@ module.exports = {
328
386
if ( this . refID ) {
329
387
this . vm . $ [ this . refID ] = null
330
388
}
389
+ var needUncache = this . asComponent || this . hasTransition
331
390
if ( this . vms ) {
332
391
var i = this . vms . length
333
392
var vm
334
393
while ( i -- ) {
335
394
vm = this . vms [ i ]
336
- this . uncacheVm ( vm )
395
+ if ( needUncache ) {
396
+ this . uncacheVm ( vm )
397
+ }
337
398
vm . $destroy ( )
338
399
}
339
400
}
@@ -360,7 +421,7 @@ module.exports = {
360
421
if ( ! cache [ id ] ) {
361
422
cache [ id ] = vm
362
423
} else {
363
- _ . warn ( 'Duplicate ID in v-repeat: ' + id )
424
+ _ . warn ( 'Duplicate track-by key in v-repeat: ' + id )
364
425
}
365
426
} else if ( isObject ( data ) ) {
366
427
id = this . id
@@ -369,7 +430,8 @@ module.exports = {
369
430
data [ id ] = vm
370
431
} else {
371
432
_ . warn (
372
- 'Duplicate objects are not supported in v-repeat.'
433
+ 'Duplicate objects are not supported in v-repeat ' +
434
+ 'when using components or transitions.'
373
435
)
374
436
}
375
437
} else {
@@ -501,4 +563,33 @@ function range (n) {
501
563
ret [ i ] = i
502
564
}
503
565
return ret
566
+ }
567
+
568
+ /**
569
+ * Helper function to overwrite new data Array on to
570
+ * existing vms. Used in `inplaceUpdate`.
571
+ *
572
+ * @param {Array } arr
573
+ * @param {Array } vms
574
+ * @param {String|undefined } alias
575
+ * @param {Boolean } converted
576
+ */
577
+
578
+ function overwrite ( arr , vms , alias , converted ) {
579
+ var vm , data , raw
580
+ for ( var i = 0 , l = arr . length ; i < l ; i ++ ) {
581
+ vm = vms [ i ]
582
+ data = raw = arr [ i ]
583
+ if ( converted ) {
584
+ vm . $key = data . $key
585
+ raw = data . $value
586
+ }
587
+ if ( alias ) {
588
+ vm [ alias ] = raw
589
+ } else if ( ! isObject ( raw ) ) {
590
+ vm . $value = raw
591
+ } else {
592
+ vm . _setData ( raw )
593
+ }
594
+ }
504
595
}
0 commit comments