|
16 | 16 | <script> |
17 | 17 | /* eslint-disable no-console */ |
18 | 18 |
|
| 19 | + const LOOP_CHECK_TIMEOUT = 1000; // the timeout for check infinite loop |
| 20 | + const LOOP_CHECK_MAX_CALLS = 10; // the maximum number of continuous calls |
19 | 21 | const SPINNERS = { |
20 | 22 | BUBBLES: 'loading-bubbles', |
21 | 23 | CIRCLES: 'loading-circles', |
|
47 | 49 | ].join('\n'), |
48 | 50 | INFINITE_EVENT: '[Vue-infinite-loading warn]: `:on-infinite` property will be deprecated soon, please use `@infinite` event instead.', |
49 | 51 | }; |
| 52 | + const ERRORS = { |
| 53 | + INFINITE_LOOP: [ |
| 54 | + `[Vue-infinite-loading error]: executed the callback function more than ${LOOP_CHECK_MAX_CALLS} times for a short time, it looks like searched a wrong scroll wrapper that doest not has fixed height or maximum height, please check it. If you want to force to set a element as scroll wrapper ranther than automatic searching, you can do this:`, |
| 55 | + ` |
| 56 | + <!-- add a special attribute for the real scroll wrapper --> |
| 57 | + <div infinite-wrapper> |
| 58 | + ... |
| 59 | + <!-- set force-use-infinite-wrapper to true --> |
| 60 | + <infinite-loading force-use-infinite-wrapper="true"></infinite-loading> |
| 61 | + </div> |
| 62 | + `, |
| 63 | + 'more details: https://github.com/PeachScript/vue-infinite-loading/issues/55#issuecomment-316934169', |
| 64 | + ].join('\n'), |
| 65 | + }; |
50 | 66 |
|
51 | 67 | export default { |
52 | 68 | data() { |
|
58 | 74 | isFirstLoad: true, // save the current loading whether it is the first loading |
59 | 75 | debounceTimer: null, |
60 | 76 | debounceDuration: 100, |
| 77 | + infiniteLoopChecked: false, // save the status of infinite loop check |
| 78 | + infiniteLoopTimer: null, |
| 79 | + continuousCallTimes: 0, |
61 | 80 | }; |
62 | 81 | }, |
63 | 82 | computed: { |
|
94 | 113 | type: String, |
95 | 114 | default: 'bottom', |
96 | 115 | }, |
| 116 | + forceUseInfiniteWrapper: null, |
97 | 117 | }, |
98 | 118 | mounted() { |
99 | 119 | this.scrollParent = this.getScrollParent(); |
|
117 | 137 | this.isFirstLoad = false; |
118 | 138 |
|
119 | 139 | if (this.isLoading) { |
120 | | - this.$nextTick(this.attemptLoad); |
| 140 | + this.$nextTick(this.attemptLoad.bind(null, true)); |
121 | 141 | } |
122 | 142 |
|
123 | 143 | if (!ev || ev.target !== this) { |
|
181 | 201 | methods: { |
182 | 202 | /** |
183 | 203 | * attempt trigger load |
| 204 | + * @param {Boolean} isContinuousCall the flag of continuous call, it will be true |
| 205 | + * if this method be called in the `loaded` |
| 206 | + * event handler |
184 | 207 | */ |
185 | | - attemptLoad() { |
| 208 | + attemptLoad(isContinuousCall) { |
186 | 209 | const currentDistance = this.getCurrentDistance(); |
187 | 210 |
|
188 | 211 | if (!this.isComplete && currentDistance <= this.distance) { |
|
193 | 216 | } else { |
194 | 217 | this.$emit('infinite', this.stateChanger); |
195 | 218 | } |
| 219 | +
|
| 220 | + if (isContinuousCall && !this.forceUseInfiniteWrapper && !this.infiniteLoopChecked) { |
| 221 | + // check this component whether be in an infinite loop if it is not checked |
| 222 | + // more details: https://github.com/PeachScript/vue-infinite-loading/issues/55#issuecomment-316934169 |
| 223 | + this.continuousCallTimes += 1; // save the times of calls |
| 224 | +
|
| 225 | + clearTimeout(this.infiniteLoopTimer); |
| 226 | + this.infiniteLoopTimer = setTimeout(() => { |
| 227 | + this.infiniteLoopChecked = true; |
| 228 | + }, LOOP_CHECK_TIMEOUT); |
| 229 | +
|
| 230 | + // throw warning if the times of continuous calls large than the maximum times |
| 231 | + if (this.continuousCallTimes > LOOP_CHECK_MAX_CALLS) { |
| 232 | + console.error(ERRORS.INFINITE_LOOP); |
| 233 | + this.infiniteLoopChecked = true; |
| 234 | + } |
| 235 | + } |
196 | 236 | } else { |
197 | 237 | this.isLoading = false; |
198 | 238 | } |
|
229 | 269 |
|
230 | 270 | if (elm.tagName === 'BODY') { |
231 | 271 | result = window; |
232 | | - } else if (['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY) > -1) { |
| 272 | + } else if (!this.forceUseInfiniteWrapper && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY) > -1) { |
233 | 273 | result = elm; |
234 | 274 | } else if (elm.hasAttribute('infinite-wrapper') || elm.hasAttribute('data-infinite-wrapper')) { |
235 | 275 | result = elm; |
|
0 commit comments