|
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