@@ -23,9 +23,11 @@ module.exports = {
2323 bind : function ( ) {
2424 // uid as a cache identifier
2525 this . id = '__v_repeat_' + ( ++ uid )
26- // setup anchor node
27- this . anchor = _ . createAnchor ( 'v-repeat' )
28- _ . replace ( this . el , this . anchor )
26+ // setup anchor nodes
27+ this . start = _ . createAnchor ( 'v-repeat-start' )
28+ this . end = _ . createAnchor ( 'v-repeat' )
29+ _ . replace ( this . el , this . end )
30+ _ . before ( this . start , this . end )
2931 // check if this is a block repeat
3032 this . template = this . el . tagName === 'TEMPLATE'
3133 ? templateParser . parse ( this . el , true )
@@ -39,6 +41,10 @@ module.exports = {
3941 this . idKey =
4042 this . _checkParam ( 'track-by' ) ||
4143 this . _checkParam ( 'trackby' ) // 0.11.0 compat
44+ // check for transition stagger
45+ var stagger = + this . _checkParam ( 'stagger' )
46+ this . enterStagger = + this . _checkParam ( 'enter-stagger' ) || stagger
47+ this . leaveStagger = + this . _checkParam ( 'leave-stagger' ) || stagger
4248 this . cache = Object . create ( null )
4349 } ,
4450
@@ -239,7 +245,9 @@ module.exports = {
239245 diff : function ( data , oldVms ) {
240246 var idKey = this . idKey
241247 var converted = this . converted
242- var anchor = this . anchor
248+ var start = this . start
249+ var end = this . end
250+ var inDoc = _ . inDoc ( start )
243251 var alias = this . arg
244252 var init = ! oldVms
245253 var vms = new Array ( data . length )
@@ -275,7 +283,7 @@ module.exports = {
275283 vms [ i ] = vm
276284 // insert if this is first run
277285 if ( init ) {
278- vm . $before ( anchor )
286+ vm . $before ( end )
279287 }
280288 }
281289 // if this is the first run, we're done.
@@ -285,45 +293,38 @@ module.exports = {
285293 // Second pass, go through the old vm instances and
286294 // destroy those who are not reused (and remove them
287295 // from cache)
296+ var removalIndex = 0
297+ var totalRemoved = oldVms . length - vms . length
288298 for ( i = 0 , l = oldVms . length ; i < l ; i ++ ) {
289299 vm = oldVms [ i ]
290300 if ( ! vm . _reused ) {
291301 this . uncacheVm ( vm )
292- vm . $destroy ( true )
302+ vm . $destroy ( false , true ) // defer cleanup until removal
303+ this . remove ( vm , removalIndex ++ , totalRemoved , inDoc )
293304 }
294305 }
295306 // final pass, move/insert new instances into the
296- // right place. We're going in reverse here because
297- // insertBefore relies on the next sibling to be
298- // resolved.
299- var targetNext , currentNext
300- i = vms . length
301- while ( i -- ) {
307+ // right place.
308+ var targetPrev , prevEl , currentPrev
309+ var insertionIndex = 0
310+ for ( i = 0 , l = vms . length ; i < l ; i ++ ) {
302311 vm = vms [ i ]
303- // this is the vm that we should be in front of
304- targetNext = vms [ i + 1 ]
305- if ( ! targetNext ) {
306- // This is the last item. If it's reused then
307- // everything else will eventually be in the right
308- // place, so no need to touch it. Otherwise, insert
309- // it.
310- if ( ! vm . _reused ) {
311- vm . $before ( anchor )
312+ // this is the vm that we should be after
313+ targetPrev = vms [ i - 1 ]
314+ prevEl = targetPrev
315+ ? targetPrev . _staggerCb
316+ ? targetPrev . _staggerAnchor
317+ : targetPrev . _blockEnd || targetPrev . $el
318+ : start
319+ if ( vm . _reused && ! vm . _staggerCb ) {
320+ currentPrev = findPrevVm ( vm , start )
321+ if ( currentPrev !== targetPrev ) {
322+ this . move ( vm , prevEl )
312323 }
313324 } else {
314- var nextEl = targetNext . $el
315- if ( vm . _reused ) {
316- // this is the vm we are actually in front of
317- currentNext = findNextVm ( vm , anchor )
318- // we only need to move if we are not in the right
319- // place already.
320- if ( currentNext !== targetNext ) {
321- vm . $before ( nextEl , null , false )
322- }
323- } else {
324- // new instance, insert to existing next
325- vm . $before ( nextEl )
326- }
325+ // new instance, or still in stagger.
326+ // insert with updated stagger index.
327+ this . insert ( vm , insertionIndex ++ , prevEl , inDoc )
327328 }
328329 vm . _reused = false
329330 }
@@ -559,12 +560,114 @@ module.exports = {
559560 this . converted = true
560561 return res
561562 }
563+ } ,
564+
565+ /**
566+ * Insert an instance.
567+ *
568+ * @param {Vue } vm
569+ * @param {Number } index
570+ * @param {Node } prevEl
571+ * @param {Boolean } inDoc
572+ */
573+
574+ insert : function ( vm , index , prevEl , inDoc ) {
575+ if ( vm . _staggerCb ) {
576+ vm . _staggerCb . cancel ( )
577+ vm . _staggerCb = null
578+ }
579+ var staggerAmount = this . getStagger ( vm , index , null , 'enter' )
580+ if ( inDoc && staggerAmount ) {
581+ // create an anchor and insert it synchronously,
582+ // so that we can resolve the correct order without
583+ // worrying about some elements not inserted yet
584+ var anchor = vm . _staggerAnchor
585+ if ( ! anchor ) {
586+ anchor = vm . _staggerAnchor = _ . createAnchor ( 'stagger-anchor' )
587+ anchor . __vue__ = vm
588+ }
589+ _ . after ( anchor , prevEl )
590+ var op = vm . _staggerCb = _ . cancellable ( function ( ) {
591+ vm . _staggerCb = null
592+ vm . $before ( anchor )
593+ _ . remove ( anchor )
594+ } )
595+ setTimeout ( op , staggerAmount )
596+ } else {
597+ vm . $after ( prevEl )
598+ }
599+ } ,
600+
601+ /**
602+ * Move an already inserted instance.
603+ *
604+ * @param {Vue } vm
605+ * @param {Node } prevEl
606+ */
607+
608+ move : function ( vm , prevEl ) {
609+ vm . $after ( prevEl , null , false )
610+ } ,
611+
612+ /**
613+ * Remove an instance.
614+ *
615+ * @param {Vue } vm
616+ * @param {Number } index
617+ * @param {Boolean } inDoc
618+ */
619+
620+ remove : function ( vm , index , total , inDoc ) {
621+ if ( vm . _staggerCb ) {
622+ vm . _staggerCb . cancel ( )
623+ vm . _staggerCb = null
624+ // it's not possible for the same vm to be removed
625+ // twice, so if we have a pending stagger callback,
626+ // it means this vm is queued for enter but removed
627+ // before its transition started. Since it is already
628+ // destroyed, we can just leave it in detached state.
629+ return
630+ }
631+ var staggerAmount = this . getStagger ( vm , index , total , 'leave' )
632+ if ( inDoc && staggerAmount ) {
633+ var op = vm . _staggerCb = _ . cancellable ( function ( ) {
634+ vm . _staggerCb = null
635+ remove ( )
636+ } )
637+ setTimeout ( op , staggerAmount )
638+ } else {
639+ remove ( )
640+ }
641+ function remove ( ) {
642+ vm . $remove ( function ( ) {
643+ vm . _cleanup ( )
644+ } )
645+ }
646+ } ,
647+
648+ /**
649+ * Get the stagger amount for an insertion/removal.
650+ *
651+ * @param {Vue } vm
652+ * @param {Number } index
653+ * @param {String } type
654+ * @param {Number } total
655+ */
656+
657+ getStagger : function ( vm , index , total , type ) {
658+ type = type + 'Stagger'
659+ var transition = vm . $el . __v_trans
660+ var hooks = transition && transition . hooks
661+ var hook = hooks && ( hooks [ type ] || hooks . stagger )
662+ return hook
663+ ? hook . call ( vm , index , total )
664+ : index * this [ type ]
562665 }
563666
564667}
565668
566669/**
567- * Helper to find the next element that is an instance
670+ * Helper to find the previous element that is an instance
568671 * root node. This is necessary because a destroyed vm's
569672 * element could still be lingering in the DOM before its
570673 * leaving transition finishes, but its __vue__ reference
@@ -575,10 +678,10 @@ module.exports = {
575678 * @return {Vue }
576679 */
577680
578- function findNextVm ( vm , anchor ) {
579- var el = ( vm . _blockEnd || vm . $el ) . nextSibling
681+ function findPrevVm ( vm , anchor ) {
682+ var el = vm . $el . previousSibling
580683 while ( ! el . __vue__ && el !== anchor ) {
581- el = el . nextSibling
684+ el = el . previousSibling
582685 }
583686 return el . __vue__
584687}
0 commit comments