|
1 | 1 | <template> |
2 | 2 | <div class="infinite-loading-container"> |
3 | 3 | <slot name="spinner"> |
4 | | - <i :class="spinnerType" v-show="isLoading"></i> |
| 4 | + <i :class="spinnerType" v-show="isLoading && !isTransitioning"></i> |
5 | 5 | </slot> |
6 | 6 | <div class="infinite-status-prompt" v-show="!isLoading && isComplete && isFirstLoad"> |
7 | 7 | <slot name="no-results">No results :(</slot> |
|
62 | 62 | isLoading: false, |
63 | 63 | isComplete: false, |
64 | 64 | isFirstLoad: true, // save the current loading whether it is the first loading |
| 65 | + isTransitioning: false, // save transition status |
| 66 | + loadedCount: 0, |
65 | 67 | }; |
66 | 68 | }, |
67 | 69 | computed: { |
|
79 | 81 | required: true, |
80 | 82 | }, |
81 | 83 | spinner: String, |
| 84 | + transition: { |
| 85 | + type: Object, // Must be a Vue transition object |
| 86 | + }, |
| 87 | + staggerCount: { |
| 88 | + type: Number, |
| 89 | + default: null, |
| 90 | + }, |
82 | 91 | }, |
83 | 92 | ready() { |
84 | 93 | this.scrollParent = getScrollParent(this.$el); |
|
94 | 103 | setTimeout(this.scrollHandler, 1); |
95 | 104 | this.scrollParent.addEventListener('scroll', this.scrollHandler); |
96 | 105 | }, |
| 106 | + methods: { |
| 107 | + listenTransitionEndOnce(callback, isReset = false) { |
| 108 | + if (this.transition) { |
| 109 | + const type = isReset ? 'afterLeave' : 'afterEnter'; |
| 110 | + const originalListener = this.transition[type]; |
| 111 | + let staggerIndex = 0; |
| 112 | +
|
| 113 | + this.isTransitioning = true; |
| 114 | + this.transition[type] = () => { |
| 115 | + // has no stagger or complete all stagger |
| 116 | + if (this.staggerCount === null || |
| 117 | + ++staggerIndex === Math.abs(this.staggerCount - this.loadedCount)) { |
| 118 | + // restore original hook |
| 119 | + if (typeof originalListener === 'function') { |
| 120 | + originalListener.call(this); |
| 121 | + this.transition[type] = originalListener; |
| 122 | + } else { |
| 123 | + delete this.transition[type]; |
| 124 | + } |
| 125 | + this.loadedCount = this.staggerCount; // save current count |
| 126 | + this.isTransitioning = false; |
| 127 | + callback.call(this); |
| 128 | + } else if (typeof originalListener === 'function') { |
| 129 | + originalListener.call(this); |
| 130 | + } |
| 131 | + }; |
| 132 | + } else { |
| 133 | + callback.call(this); |
| 134 | + } |
| 135 | + }, |
| 136 | + }, |
97 | 137 | events: { |
98 | 138 | '$InfiniteLoading:loaded': function loaded() { |
99 | | - this.isLoading = false; |
100 | | - this.isFirstLoad = false; |
| 139 | + this.listenTransitionEndOnce(() => { |
| 140 | + this.isLoading = false; |
| 141 | + this.isFirstLoad = false; |
| 142 | + }); |
101 | 143 | }, |
102 | 144 | '$InfiniteLoading:complete': function complete() { |
103 | | - this.isLoading = false; |
104 | | - this.isComplete = true; |
105 | | - this.scrollParent.removeEventListener('scroll', this.scrollHandler); |
| 145 | + this.listenTransitionEndOnce(() => { |
| 146 | + this.isLoading = false; |
| 147 | + this.isComplete = true; |
| 148 | + this.scrollParent.removeEventListener('scroll', this.scrollHandler); |
| 149 | + }); |
106 | 150 | }, |
107 | 151 | '$InfiniteLoading:reset': function reset() { |
108 | | - this.isLoading = false; |
109 | | - this.isComplete = false; |
110 | | - this.isFirstLoad = true; |
111 | | - this.scrollParent.addEventListener('scroll', this.scrollHandler); |
112 | | - setTimeout(this.scrollHandler, 1); |
| 152 | + this.listenTransitionEndOnce(() => { |
| 153 | + this.isLoading = false; |
| 154 | + this.isComplete = false; |
| 155 | + this.isFirstLoad = true; |
| 156 | + this.scrollParent.addEventListener('scroll', this.scrollHandler); |
| 157 | + setTimeout(this.scrollHandler, 1); |
| 158 | + }, true); |
113 | 159 | }, |
114 | 160 | }, |
115 | 161 | destroyed() { |
|
0 commit comments