What is IntersectionObserver API?

The Intersection Observer API provides a way to asynchronously observe changes in the Intersection of a target element with an ancestor element or a top-level document viewport. Allows you to configure a callback function to be executed whenever the target element intersects the device window or other specified element.

Transform the vue – scroll – loader

Vue-scroller-loader is one of the components of element UI library that I used. Due to the inexplicable Bug of the infinite scroll component of element UI library, the issue has not been fixed for a long time. So the self (Chong) force (Fu) force (Zao) force (ZI) force (LUN) force (zi) a similar infinite rolling component, simple enough, small enough.

Prior to the use of the Observer API, vue-Scorll-loader 1.x was implemented using the ancient technique of listening to the scroll bar. This method, as anyone with common sense knows, has performance costs. In addition, the official Polyfill can be used in production environment, and it is amazing that kang Yu’s old code has been transformed into just a few lines.

One, realize the main structure of the component

Instead of creating a warpper to wrap the list to be loaded in a normal way, I directly use a loading animation to place it under the list. Loding is the component itself, so that the component is decoupled from the list and has nothing to do with layout. List uses infinite scrolling to drop this component directly below it without additional changes to the list layout

CSSFX

HTML

Provides the ability to customize animations using slot

<template lang="html">
  <div class="loader" v-show=! "" loaderDisable">
    <slot>
      <svg viewBox="25 25 to 50 50" class="loader__svg" :style="size">
        <circle cx="50" cy="50" r="20" class="loader__circle" :style="color"></circle>
      </svg>
    </slot>
  </div>
</template>
Copy the code

SCSS

<style lang="scss" scoped>
.loader{
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 30px 0;
  &__svg {
    transform-origin: center;
    animation: rotate 2s linear infinite;
  }
  &__circle {
    fill: none;
    stroke-width: 3;
    stroke-dasharray: 1, 200;
    stroke-dashoffset: 0;
    stroke-linecap: round;
    animation: dash 1.5s ease-in-out infinite;
  }
}
@keyframes rotate {
  100% {
    transform: rotate(360deg);
  }
}
@keyframes dash {
  0% {
    stroke-dasharray: 1, 200;
    stroke-dashoffset: 0;
  }
  50% {
    stroke-dasharray: 90, 200;
    stroke-dashoffset: -35px;
  }
  100% {
    stroke-dashoffset: -125px;
  }
}
</style>
Copy the code

DEMO

Two, realize the main functions of the components

Previously we were listening for a scrollbar implementation like this:

Disadvantages: Synchronous, and can trigger repeatedly, often requiring debounce limit frequency, requiring manual calculation of relative position.

window.addEventListener('scroll', e => {// a bunch of calculation code... })Copy the code

Now use the Intersection Observer API:

Advantages: asynchronous, only triggered at intersections, no need to calculate the relative positions of elements.

Const observer = new IntersectionObserver(([{isIntersecting}]) => {// What to do... }, {root: null, // the relative viewport element, passing null to the top-level document viewport rootMargin:'0px 0px 0px 0px', // The offset of the observed element relative to the viewport when the cross callback is triggered threshold: 0 // a specific value or array of values, the visible ratio of the observed element when the cross callback is triggered}) // Pass in the observed element observer.observe(el)Copy the code

You may have noticed that I received an isIntersecting parameter in the callback above. What does this do? The reason for this is that when the observed element passes through the viewport intersection, two callbacks are triggered, one into the intersection and one out of the intersection. Entering is true and leaving is false, so we need this parameter to ensure that the load callback fires only once.

Here is the implementation of infinite scrolling in conjunction with Vue.

JAVASCRIPT & VUE

<script>
import 'intersection-observer'
export default {
  name: 'ScrollLoader',
  props: {
    'loader-method': {
      type: Function,
      required: true
    },
    'loader-disable': {
      type: Boolean,
      default: false
    },
    'loader-distance': {
      type: Number,
      default: 0
    },
    'loader-color': {
      type: String,
      default: '# 666666'
    },
    'loader-size': {
      type: Number,
      default: 50
    },
    'loader-viewport': {
      type: Element,
      default: null
    }
  },
  computed: {
    size () {
      return {
        width: `${this.loaderSize}px`
      }
    },
    color () {
      return {
        stroke: this.loaderColor
      }
    },
    options () {
      return {
        root: this.loaderViewport,
        rootMargin: `0px 0px ${this.loaderDistance}px 0px`
      }
    },
    observer () {
      returnnew IntersectionObserver(([{ isIntersecting }]) => { isIntersecting && ! this.loaderDisable && this.loaderMethod() }, this.options) } },mounted () {
    this.observer.observe(this.$el)},activated () {
    this.observer.observe(this.$el)},deactivated () {
    this.observer.unobserve(this.$el)},beforeDestroy () {
    this.observer.unobserve(this.$el)
  }
}
</script>
Copy the code

Here is a trick: New IntersectionObserver() will create an observer. Since the observer needs to be unregistered when leaving the current component, this observer will be created using the calculated property while remaining resident. This simplifies the operation of new IntersectionObserver() in Mounted () and storing the instance in data.

DEMO

Preview online: DEMO

Project address: vue-scroll-loader

conclusion

The first time in nuggets published articles, not what dry goods, is not very advanced technology, but still hope this article can help to the front of the chicken like me, if there are omissions or mistakes in the article, also hope big guy advice, thank you!