vue implements rolling load instruction

Posted by arlabbafi on Mon, 07 Mar 2022 17:47:21 +0100

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

Topics: Javascript JQuery Vue Vue.js