|
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