广州商学院,90行代码和15个元素教你如何无限滚动。-anggame安博电竞-安博电竞竞猜-安博电竞 官网

暖心故事 301℃ 0

作者 | 前端劝退师

责编 | 胡巍巍

在本篇文章你将会学到:

  • IntersectionObserver API的用法,以及怎么兼容。

  • 怎么在React Hook中完成无限翻滚。

  • 怎么正确烘托多达10000个元素的列表。

无限下拉加载技能运用户在许多成块的内容面前一向翻滚检查。这种办法是在你向下翻滚的时分不断加载新内容。

当你运用翻滚作为发现数据的首要办法时,它可能使你的用户在网页上逗留更长时刻并提高用户参加度。

跟着交际媒广州商学院,90行代码和15个元素教你怎么无限翻滚。-anggame安博电竞-安博电竞竞猜-安博电竞 官网体的盛行,许多的数据被用户消费。广州商学院,90行代码和15个元素教你怎么无限翻滚。-anggame安博电竞-安博电竞竞猜-安博电竞 官网无线翻滚供给了一个高效的办法让用户阅读海量信息,而不用等候页面的预加载。

怎么构建一个体会杰出的无限翻滚,是每个前端无论是项目或面试都会碰到的一个课题。

前期的解决方案

关于无限翻滚,前期的解决方案根本都是依靠监听scroll事情:

function fetchData {
fetch(path).then(res => doSomeThing(res.data));
}

window.addEventListener('scroll', fetchData);

然后核算各种.scrollTop、.offset.top等等。

手写一个也是十分单调。并且:

  • scroll事情会频频触发,因而咱们还需求手动节省。

  • 翻滚元素内有许多DOM,简略形成卡顿。

穿插调查者:IntersectionObserver

const box = document.querySelector('.box');
const intersectionObserver = new I孙文禹ntersectionObserver((entries) => {
entries.forEach((item) => {
if (item.isIntersecting) {
console.log('进入可视区域');
}
})
});
intersectionObserver.observe(box);

敲要点:IntersectionObserver API是异步的,不跟着方针元素的翻滚同步触发,功能耗费极低。

2.1 IntersectionObserverEntry方针

这儿我就大略的介绍下需求用到的:IntersectionObserverEntry方针。

callback函数被调用时,会传给它一个数组,这个数组里的每个方针便是当时进入可视区域或许脱离可视区域的方针(IntersectionObserverEntry方针)

这个方针有许多特点,其间最常用的特点是:

  • target: 被调查的方针元素,是一个 DOM 节点方针

  • isIntersecting: 是否进入可视区域

  • intersectionRatio: 相交区域和方针元素的份额值,进入可视区域,值大于0,不然等于0

2.3 options

调用IntersectionObserver时,除了传一个回调函数,还能够传入一个option方针,装备如下特点:

  • threshold: 决议了什么时分触发回调函数。它是一个数组,每个成员都是一个门槛值,默以为[0],即穿插份额(intersectionRatio)到达0时触发回调函数。用户能够自界说这个数组。比方,[0, 0.25, 0.5, 0.75, 1]就表明当方针元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。

  • root: 用于调查的根元素,默许是阅读器的视口,也能够指定详细元素,指定元素的时分用于调查的元素有必要是指定元素的子元素

  • rootMargin: 用来扩展或许缩小视窗的的巨细,运用css的界说办法,10px 10px 30px 20px表明top、right、bottom 和 left的值

const io = new IntersectionObserver((entries) => {
console.log(entries);
}, {
threshold: [0, 0.5],
root: document.querySelector('.container'),
rootMargin: "10px 10px 30px 2我的自豪无可救药0px",
});
2.4 observer
observ小规模交税人和一般交税人的差异er.observer(nodeone); //仅调查nodeOne 
observer.observer(nodeTwo); //调查nodeOne和nodeTwo
observer.unobserve(nodeOne); //中止调查nodeOne
observer.disconnect; //没有调查任何节点

怎么在React Hook中运用IntersectionObserver

在看Hooks版之前,来看正常组件版的:

class SlidingWindowScroll extends React.Component {
this.$bottomElement = React.createRef;
...
componentDidMount {
this.intiateScrollObserver;
}
intiateScrollObserver = => {
const options = {
root: ,
rootMargin: '0px',
threshold: 0.1
};
this.observer = new IntersectionObserver(this.callback, options);
this.observer.observe(this.$bottomElement.current);
}
render {
return (
<li className='img' ref={this.$bottomElement}>
)
}

众所周知,React 16.x后推出了useRef来代替原有的createRef,用于追寻DOM节点。那让咱们开端吧:

原理

完成一个组件,能够显现具有15个元素的固定窗口巨细的n个项目的列表:

即在任何时分,无限翻滚n元素上也仅存在15个DOM节点。

  • 选用relative/absolute 广州商学院,90行代码和15个元素教你怎么无限翻滚。-anggame安博电竞-安博电竞竞猜-安博电竞 官网定位来确认翻滚位正月十三置

  • 追寻两个ref: top/bottom来决议向上/向下翻滚的烘托与否

  • 切开数据列表,保存最多15个DOM元素。

useState 声明状态变量

咱们开端编写组件SlidingWindowScrollHook:

const THRESHOLD = 15;
const SlidingWindowScrollHook = (p白杨rops) => {
const [十二生肖故事start, setStart] = useState(0);
const [end, setEnd] = useState(THRESHOLD);
const [observer, setObserver] = useState;
// 其它代码...
}

1. useState 的简略了解:

const [特点, 操作特点的办法] = useState(默许值);

2. 变量解析

  • start:当时烘托的列表第一个数据,默以为0

  • end: 当时烘托的列表最终一个数据,默以为15

  • observer: 当时调查的视图ref元素

useRef 界说追寻的DOM 元素

const $bottomElement = useRef;
const $topElement = useRef;

正常的无限向下翻滚只需重视一个dom元素,但由于咱们是固定15个dom元素烘托,

需求判别向上或向下翻滚otg。

内部操作办法和和对应useEffect

请合作注释食用:

useEffect( => {
// 界说调查
intiateScroll广州商学院,90行代码和15个元素教你怎么无限翻滚。-anggame安博电竞-安博电竞竞猜-安博电竞 官网Observer;
return => {
// 抛弃调查
resetObservation
}
},[end]) //由于[end] 是同步改写,这儿用一个就行了。

// 界说调查
const intiateScro广州商学院,90行代码和15个元素教你怎么无限翻滚。-anggame安博电竞-安博电竞竞猜-安博电竞 官网llObserver = => {
const options = {
root: ,
rootMargin: '0px',
threshold: 0.1
};
const Observer = new IntersectionObserver(callback, options)
// 别离调查最初和结束的元素
if ($topElement.current) {
Observer.observe($topElement.current);
}
if ($bottomElement.current) {
Observer.observe($bottomElement.current);
}
// 设初始值
setObserver(Observer)
}

// 穿插调查的详细回调,调查每个节点,并对实时头尾元素索引处理
const callback = (entries, observer) => {
entries.forEach((entry, index) => {
const listLength = props.list.length;
// 向下翻滚,改写数据
if (entry.isIntersecting && entry.target.id === "bottom") {
const maxStartIndex = listLength - 1 - THRESHOLD; // 当时头部的索引
const max广州商学院,90行代码和15个元素教你怎么无限翻滚。-anggame安博电竞-安博电竞竞猜-安博电竞 官网EndIndex = listLength - 1; // 当时尾部的索引
const newEnd = (end + 10) <= maxEndIndex ? end + 10 : maxEndIndex; // 下一轮添加尾部
const范治刚 newStart = (end - 5) <= maxStartIndex ? end - 5 : maxStartIndex; // 在上一轮的基础上核算头部
setStart(newStart)
setEnd(newEnd)
}
// 向上翻滚,改写数据
if (entry.isIntersecting && entry.target.id === "top") {
const newEnd = end === THRESHOLD ? THRESHOLD : (end - 10 > THRESHOLD ? end - 10 : THRESHOLD); // 向上翻滚尾部元素索引不得小于15
let newStart = start === 0 ? 0 : (start - 10 > 0 ? start - 10 : 0); // 头部元素索引最小值为0
setStart(newStart)
setEnd(newEnd)
}
});
}

// 中止翻滚时抛弃调查
const resetObservation = => {
observer && observer.unobserve($bottomElement.current);
observer && observer.unobserve($topElement.current);
}

// 烘托时,头尾ref处理
const getReference = (index, isLastIndex) => {
if (index === 0)
rcompromiseeturn $topElement;
if (isLastIndex)
return $bottomElement;
return ;
}

烘托界面

 const {list, height} = props; // 数据,节点高度
const updatedList = list.slice(start, end); // 数据切开

const lastIndex = updatedList.length - 1;
return (

    {updatedList.map((item, index) => {
    const top = (height * (index + start)) +大三元 'px'; // 根据相对 & 肯定定位 核算
    const refVal = getReference(index, index === lastIndex); // map循环中赋予头尾ref
    const id = index === 0 ? 'top' : (index === lastIndex ? 'bottom' : ''); // 绑ID
    return (<li className="li-card" key={item.key} style={{top}} ref={refVal} id={id}>{item.value}li>);
    })}

);

怎么运用

App.js:

import React from 'react';
import './App.css';
import { SlidingWindowScrollHook } from "./SlidingWindowScrollHook";
import MY_ENDLESS_LIST from './Constants';
function App {
return (
App">

15个元素完成无限翻滚


lHook list={MY_ENDLESS_LIST} height={195}/>

);
}

export default App;
界说一下数据 Constants.js:
const MY_ENDLESS_LIST = [
{
key: 1伊利股份,
value: 'A'
},
{
key: 2,
value: 'B'
},
{
key: 3,
value: 'C'
},
// 中心就不贴了...
{
key: 45,
value: 'AS'
}
]

SlidingWindowScrollHook.js:

import React, { useState, useEffect, useRef } from "react";
const THRESHOLD = 15;

const SlidingWindowScrollHook = (props) => {
const [start, setStart] = useState(0);
const [end, setEnd] = useState(THRESHOLD);
const [observer, setObserver大成oa] = useState;
const $bottomElement = useRef;
const $topElement = useRef;

useEffect( => {
intiateScrollObserver;
return => {
resetObservation
}
// eslint-disable-next-line react-hooks/exhaustive-deps
},[start, end])

const intiateScrollObserver = => {
const options = {
root: ,
rootMargin: '0px',
threshold: 0.1
};
const Observer = new IntersectionObserver(callback, options)
if ($topElement.current) {
Observer.observe($topElement.current);
}
if ($bottomElement.current) {
Observer.observe温顺($bottomElement.current);
}
setObserver(Observer)
}

const callback = (entries, observer) => {
entries.forEach((entry, index) => {
c广州商学院,90行代码和15个元素教你怎么无限翻滚。-anggame安博电竞-安博电竞竞猜-安博电竞 官网onst listLength = props.list.length;
// Scroll Down
if (entry.isIntersecting && entry.target.id === "bottom") {
const maxStartIndex = listLength - 1 - THRESHOLD; // Maximum index value `start` c受an take
const maxEndIndex = listLength - 1; // Maximum index value `end` can take
const newEnd = (end + 10) <= maxEndIndex ? end + 10 : maxEndIndex;
const newStart = (end - 5) <= maxStartIndex ? end - 5 : maxStartIndex;
setStart(newStart)
setEnd(newEnd)
}
// Scroll up
if (entry.isIntersecting && entry.target.id === "top") {
const newEnd = end === THRESHOLD ? THRESHOLD : (end - 10 > THRESHOLD ? end - 支付宝登录10 : THRESHOLD);
let newStart = start === 0 ? 0 : (start - 10 > 0 ? start - 10 : 0);
setStart(newStart)
setEnd(newEnd)
}

});
}
const resetObservation = => {
observer && observer.unobserve($bottomElement.current);
observer && observer.unobserve($topElement.current);
}


const getReference = (index, isLastIndex) => {
if (index === 0)
return $topElement;
if (isLastIndex)
return $bottomElement;
return ;
}

const {list, height} = props;
const updatedList = list.slice(start, end);
const lastIndex = updatedList.length - 1;

return (

    {updatedList.map((item, index) => {
    const top = (height * (index + start)) + 'px';
    const refVal = getReference(index, index === lastIndex);
    const id = index === 0 ? 'top' : (index === lastIndex ? 'bottom' : '');
    return (<li className="li-card" key={item.key} style={{top}} ref={refVal} id={id}>{item.value}li>);
    })}

);
}
export { SlidingWindowScrollHook };

以及少手机修理许款式:

.li-card {
display: flex;
justify-content: center;
list-style: none;
box-shadow: 2px 2px 9px 0px #bbb;
padding: 70px 0;
margin-bottom: 20px;
border-radius: 10px;
position: absolute;
width: 80%;
}

然后你就能够渐渐耍了。

兼容性处理

IntersectionObserver不兼容Safari?

莫慌。咱们有polyfill版。

每周34万下载量呢,定心用吧。

项目源地址:https甘肃地图://github.com/roger-hiro/SlidingWindowScrollHook

材料:

  • Creating Infinite Sc欧拉r微信签名oll with 15 Elements

  • IntersectionObserve初试

【END】

标签: strawberry敖胥