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 to
overflow: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