plan


There are several common ways to achieve the sliding top suction effect:

1.positon: sticky

2. Listen for the element’s scroll event, using offset

3.obj.getBoundingClientRect().top

Here is the sequence

positon: sticky


Postion: Sticky attribute value is a new attribute added by CSS3, which is approximately the combination of relative and fixed

Sticky is referred to as sticky positioning element, and the element with postion attribute value is the same as position: relative when it is in the target area.

When an element meets a sticky positioning requirement (top: 100px), it behaves like position: fixed

The fixed relative offset of an element is relative to its nearest scrollable ancestor, or, if none of the ancestors can be scrolled, relative to the viewPort.

Conditions of use:

  • The parent element cannot be set tooverflow:hidden/auto
  • Fixed (top, bottom, right, left); fixed (relative
  • The height of the parent element cannot be lower than that of the Skicky element

Pit:

  • The sticky element is homogenous and only works within its own qualified ancestor container.
  • Although the sticky element presents position: fixed when it meets the sticky condition, it does not trigger BFC
  • Sticky elements are not valid for z-index in stylesheets, if you want to use z-index attributes you can write them in inline styles

Compatibility:

Compatibility is not very friendly, although ios support is ok, but the performance of the screen bangs is still to be determined

Usage:

.sticky{
    positon: sticky;
    top: 10px
}
Copy the code

Listen for the scroll event — offset


First, let’s review the meanings of the following offset values:

The top offset from the parent element that has relative positioning

So offset doesn’t necessarily represent the distance from the top of the page, but it could also be the distance from the top of the parent element that has relative positioning

Assuming that the top effect we want is at the top of the body, we can modify a method as follows

getOffset(obj,direction) {
    let offsetL = 0;
    letoffsetT = 0; // Get the offsetLeft/offsetTop of the parent elementswhile( obj! == window.document.body && obj ! == null ){ offsetL += obj.offsetLeft; offsetT += obj.offsetTop; obj = obj.offsetParent; }if(direction === 'left') {return offsetL;
    }else {
        return offsetT;
    }
}

handleScroll(e) {
    let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
    let offsetTop = getOffset(e.target,'top');
    if(scrollTop > offsetTop){
        // fixed
    }
}


Copy the code

Advantages: Excellent compatibility

Disadvantages: It has performance problems and is best used with throttling functions

Listening to scroll event – obj. GetBoundingClientRect (). The top


Definition: Returns the distance of an element relative to the browser window

In other words, this API can completely replace the above function…

Compatibility:

Advantages: simple and clean, and capacitive very good

Disadvantages: Does not solve the performance problem of excessive reflow

Performance optimization


As we all know, scroll problems can’t escape the performance pressure of high intensity reflow

The solution is pretty clear — sacrifice smoothness and reduce the number of triggers

throttle

In general, we can use the throttling function directly to limit the number of triggers, such as this

// If you are assigning throttle(func,time) to window.addeventListener ('scroll', throttle(handleScroll, 20));
Copy the code

But there’s a problem with using it this way. That is, there will be a certain number of cards at the top of the situation, not embellish.

So what do we do?

Let’s look at it another way… How about controlling exactly when the handleScroll() function fires?

Naturally, the IntersectionObserver API came to mind

IntersectionObserver API

For details on how to use IntersectionObserver API, please go here

The main purpose of this API is to determine if an element is visible (and to control when it fires)

Compatibility:

It’s not hard to see that there are a few compatibility issues. Therefore, it is better to combine throttle and IntersectionObserver schemes

Combined with scheme

this.flag == false

scrollFunc(e) {
    if( IntersectionObserver ){
        const observer = new IntersectionObserver(function(){
            const offsetTop = e.target.getBoundingClientRect().top;
            if(offsetTop < 0){// this. Flag ==true
            }else{
                this.flag == false}}, {// when 100% trigger callback function threshold: [1]}); observer.observe(e.target); }else {
        window.addEventListener('scroll', throttle(()=>{
            let offsetTop = e.target.getBoundingClientRect().top;
            if(offsetTop < 0){// this. Flag ==true
            }else{
                this.flag == false}}, 20)); }}Copy the code