background

In long list display, considering the screen size of mobile terminal, there is rarely the interaction design of page-turning on PC terminal, and considering the page performance, it is not possible to load all the data at one time. Instead, more data can be loaded by pull-up in the list of mobile terminal.

There are a number of component libraries that implement this basic functionality, such as ListView in antd-mobile@2, but the general configuration items can be cumbersome to use.

The principle of

In fact, the principle of “loading more” is also relatively simple, first get the total length of the list and the first page of data, if the first page of data length is less than the total length of the list, add “loading…” at the bottom of the list. Listen for page scrolling events if the bottom “loading…” When the element appears in the viewable area, we request data for the next page and continue listening for scrolling events on the page until the current list displays data equal the total length of the list.

So the main technical point is: how to tell the bottom “loading…” Element appears in viewable area?

The first thing you might think of is listening to the page scroll and then dynamically calculating the “loading…” at the bottom of the page. Element position.

Listen for page scrolling

Use react as an example:

useEffect(() = > {
    function onTouchMove() {
			// do something...
    }

    document.addEventListener('touchmove', onTouchMove)

    return () = > {
      document.removeEventListener('touchmove', onTouchMove)
    }
  }, [])
Copy the code

PS: Scrollmonitoring generally needs to be considered plus throttling functions.

Alternatively, you can use requestAnimationFrame to continuously calculate instead of listening for scrolling. If you are not familiar with this API, you can check MDN:

const requestRef = useRef()
const scrollCb = () = > {
    // do something...
    requestRef.current = requestAnimationFrame(scrollCb)
}
  
useEffect(() = > {
    requestRef.current = requestAnimationFrame(scrollCb)
    return () = > cancelAnimationFrame(requestRef.current)
}, [])
Copy the code

Visual area detection

The bottom “loading…” There are three options for whether or not an element appears in the viewable area:

  • OffsetTop, scrollTop

OffsetTop: The pixel distance between the top outer border of an element and the top inner border of the containing element.

ScrollTop: The scrollTop value of an element is a measure of the distance from the top of the element’s content (rolled up) to its viewport visible content (top). When the content of an element does not produce a vertical scroll bar, its scrollTop value is 0.

function isInViewPortOfOne (el) {
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const offsetTop = el.offsetTop
    const scrollTop = document.documentElement.scrollTop
    const top = offsetTop - scrollTop
    return top <= viewPortHeight
}
Copy the code
  • getBoundingClientRect

Element. GetBoundingClientRect () method returns the Element size and its position relative to the viewport. MDN

function isInViewPort(element) {
  const viewWidth = window.innerWidth || document.documentElement.clientWidth;
  const viewHeight = window.innerHeight || document.documentElement.clientHeight;
  const {
    top,
    right,
    bottom,
    left,
  } = element.getBoundingClientRect();

  return (
    top >= 0 &&
    left >= 0 &&
    right <= viewWidth &&
    bottom <= viewHeight
  );
}
Copy the code
  • Intersection Observer

The Intersection Observer is used to determine whether two elements overlap because it performs better than the getBoundingClientRect function, which does not monitor events.

It’s very simple to use.

var io = new IntersectionObserver(callback, option);
Copy the code

In the above code, IntersectionObserver is the constructor provided natively by the browser and takes two parameters: callback is the callback function when visibility changes and option is the configuration object (this parameter is optional).

The return value of the constructor is an observer instance. The observe method of the instance specifies which DOM node to observe.

// Start observing
io.observe(document.getElementById('example'));

// Stop observing
io.unobserve(element);

// Close the viewer
io.disconnect();
Copy the code

In the code above, the argument to Observe is a DOM node object. Call this method multiple times if you want to observe multiple nodes.

io.observe(elementA);
io.observe(elementB);
Copy the code

Recommend solutions and implementations

Intersection Observer From the above, we can conclude that using the Intersection Observer is the simplest and best performing solution.

React.js is used as an example:

  // data indicates the current list data, and total indicates the total number of lists
  // load-more is the id of the "load more" element at the bottom
  // Process loads more
  useEffect(() = > {
    if (data.length < total && document.querySelector('#load-more')) {
      const intersectionObserver = new IntersectionObserver(function (entries) {
        // If not visible, return
        if (entries[0].intersectionRatio <= 0) return
        
        // Trigger to load moretriggerLoadMore? . ()})// Start observing
      intersectionObserver.observe(document.querySelector('#load-more'))

      return () = > {
        intersectionObserver.disconnect()
      }
    }
  }, [data, total])
Copy the code

As you can see, the implementation code is simple, and we don’t need to listen for scrolling events anymore.

compatibility

As you can see from the table above, the API is already fairly compatible.

The W3C also provides a polyfill for this API, see W3C /IntersectionObserver.

In daily development, it is recommended to introduce compatible code directly using Polyfill. IO:

<script src="https://polyfill.io/v3/polyfill.min.js? features=IntersectionObserver"></script>Copy the code

Other optimization points

  • Add virtual scroll

Simple understanding, virtual scrolling is in the browser, only render the current visual area of the content, through the user to slide the position of the scroll bar to dynamically calculate the display of the content, the rest of the blank fill to give the user the illusion of a long list, can solve the long list of page sliding delays and other problems. React-window can be used to implement virtual scrolling in react. js. You can look it up on your own, but I won’t expand on it here.

Share

Welcome to visit our small program small program small program front end test treasure book, which has collected 600+ common front end test questions and answers, I hope to help students on the way to interview.

Please also visit our recently updated article:

The front end social magic policy data two rounds of surface

Millward Brown front three aspects (technical side 2 +HR side)

Bytedance commercial front-end interview

Meituan four rounds of interviews

Iqiyi front two face classics

Meanwhile, welcome to follow our team’s other gold digging account:

Front end face of digging gold test treasure book

The resources

  • IntersectionObserver API usage tutorial

  • Interviewer: How do you tell if an element is in the viewable area?

  • The second complete front end of the universe