Scroll loading instructions, with source code and use cases, can be used directly.
Background:
Rolling paging is required in the project, but it will be triggered when rendering with v-infinite-scroll, so you can implement the rolling loading instruction instead
prerequisite:
- jquery.js: jQuery is used to calculate the element height, which can be replaced by native JavaScript
- lodash.js: use lodash to handle rolling throttling. You can cancel throttling or replace it with native JavaScript implementation
Realization idea:
By listening to the scrolling event, it is judged that the loading event will be triggered when scrolling to the bottom
How to determine whether to scroll to the bottom:
Here, we judge whether the rolling distance in the container is greater than or equal to the difference between the height of all children of the container (including border, padding and margin) minus the height of the container itself. If it is satisfied, it is considered to have rolled to the bottom
Rolling distance > = child height - self height
If we set the container as container, then:
Height of all children of container: you can traverse its direct children and calculate the sum of offset height of children
Rolling distance of container: it can be obtained through scrollTop() of jquery
Height of container: it can be obtained through jquery's height()
We have a general idea. Next, we will use the instructions of vue to realize rolling loading
We used custom instructions directives The inserted hook
Inserted: called when the bound element is inserted into the parent node (only the parent node is guaranteed to exist, but it may not have been inserted into the document).
inserted will accept three parameters, El, binding and vnode. Here we only use el and binding
el is our container instance, and $(el) can get the dom of the container.
binding.value is the event we bind, for example, v-load-more = "loadMore", binding Value is loadMore
Code implementation:
Code implementation of v-load-more instruction:
directives: { /* By judging the rolling distance > = child height - self height If true, the bottom is considered reached */ loadMore: { inserted(el, binding) { const scrollFn = () => { // Child height let scrollH = 0 $(el).children().each((idx, item) => { scrollH += $(item).get(0).offsetHeight }) let wrapH = $(el).height() // Own height let scrollT = $(el).scrollTop() // Rolling distance let isBottom = scrollT >= scrollH - wrapH if (isBottom) { binding.value && binding.value() // binding.value gets the bound event } } // Use lodash's throttle function for throttling $(el).on('scroll', _.throttle(scrollFn, 100)) } } },
Use cases attached
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script> </head> <body> <div id="app"> <div class="list-container" v-load-more="loadMore"> <div> <div class="list-item" v-for="(item, idx) in list" :key="idx"> {{item}} </div> </div> </div> </div> </body> </html> <script> var app = new Vue({ el: '#app', data: { list: 20, }, directives: { /* By judging the rolling distance > = child height - self height If true, the bottom is considered reached */ loadMore: { inserted(el, binding) { const scrollFn = () => { // Child height let scrollH = 0 $(el).children().each((idx, item) => { scrollH += $(item).get(0).offsetHeight }) let wrapH = $(el).height() // Own height let scrollT = $(el).scrollTop() // Rolling distance let isBottom = scrollT >= scrollH - wrapH if (isBottom) { binding.value && binding.value() } } $(el).on('scroll', _.throttle(scrollFn, 100)) } } }, methods: { loadMore() { this.list += 20 } }, }) </script> <style> .list-container { margin: 0 auto; height: 700px; width: 600px; overflow-y: auto; } .list-item { line-height: 60px; text-align: center; background: #ccc; border-bottom: 1px solid #fff; } </style>
ps: please indicate the source for reprint