npm i intersection-observer
// 顶部引入
import 'intersection-observer';
// 字段解析
loadingText: PropTypes.string, // 加载文字
loadingIon: PropTypes.any, // 加载图标 不添加为默认
finish: PropTypes.bool, // 是否完成
next: PropTypes.func, // 下一次触发的函数
0.初始准备工作
constructor(props) {
super(props);
this.state = {
loading: false,
};
// 获取当前的ref好控制当前元素是否到视窗
this.ref = React.createRef();
}
1.一开始先定义好intersection-observer
componentDidMount() {
// IntersectionObserver polyfill 文档添加
IntersectionObserver.prototype.USE_MUTATION_OBSERVER = false;
const node = this.ref.current;
this.observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 添加判断显示的是否为加载还是完成
this.setState({ loading: true });
// 暂停监听 避免再loading时还触发
observer.unobserve(node);
// 调用方法
this.dataLoading();
}
});
}, {
// 增加视口 范围
rootMargin: '0px 0px 100px 0px',
});
this.observer.POLL_INTERVAL = 500;
this.observer.USE_MUTATION_OBSERVER = false;
this.observer.observe(node); // 运行
}
componentWillUnmount() {
this.listener1.remove(); // 销毁时删除
}
3.被调用时执行的函数
async dataLoading() {
try {
await this.props.next(); // 调用传入的方法 用于loading数据
} finally {
this.setState({ loading: false });
if (!this.props.finish) { // finish判断是否已经完成达到了最后一条数据
this.observer.observe(this.ref.current);
}
}
}
4.显示的样式
renderContent() {
const { loadingText, loadingIon, finish, next, ...layoutProps } = this.props;
const { loading } = this.state;
return (
<FlexRowContainer
{...layoutProps}
width="match_parent"
height="20px"
justifyContent="center"
ref={this.ref} // 获取ref
fontSize="14px"
>
{loading && // 为加载时显示的样式
<FlexRowContainer
width="wrap_content"
height="wrap_content"
fontSize="13px"
>
<scmp.Span
width="wrap_content"
height="wrap_content"
fontSize="13px"
>
{loadingText || 'loading'}
</scmp.Span>
{loadingIon || <DotLoading />}
</FlexRowContainer>}
{finish && // 完成时显示的样式
<scmp.Span
width="wrap_content"
height="wrap_content"
fontSize="12px"
>
--- There are no more goods ---
</scmp.Span>}
</FlexRowContainer>
);
}
5.完整代码
1 class ScrollLoad extends BaseComponent {
2 constructor(props) {
3 super(props);
4 this.state = {
5 loading: false,
6 };
7 // 获取当前的ref好控制当前元素是否到视窗
8 this.ref = React.createRef();
9 }
10
11 componentDidMount() {
12 // IntersectionObserver polyfill 文档添加
13 IntersectionObserver.prototype.USE_MUTATION_OBSERVER = false;
14
15 const node = this.ref.current;
16 this.observer = new IntersectionObserver((entries, observer) => {
17 entries.forEach((entry) => {
18 if (entry.isIntersecting) {
19 // 添加判断显示的是否为加载还是完成
20 this.setState({ loading: true });
21 // 暂停监听 避免再loading时还触发
22 observer.unobserve(node);
23 // 调用方法
24 this.dataLoading();
25 }
26 });
27 }, {
28 // 增加视口 范围
29 rootMargin: '0px 0px 100px 0px',
30 });
31 this.observer.POLL_INTERVAL = 500;
32 this.observer.USE_MUTATION_OBSERVER = false;
33 this.observer.observe(node); // 运行
34 }
35
36 componentWillUnmount() {
37 this.listener1.remove(); // 销毁时删除
38 }
39
40 async dataLoading() {
41 try {
42 await this.props.next(); // 调用传入的方法 用于loading数据
43 } finally {
44 this.setState({ loading: false });
45 if (!this.props.finish) { // finish判断是否已经完成达到了最后一条数据
46 this.observer.observe(this.ref.current);
47 }
48 }
49 }
50
51 renderContent() {
52 const { loadingText, loadingIon, finish, next, ...layoutProps } = this.props;
53 const { loading } = this.state;
54 return (
55 <FlexRowContainer
56 {...layoutProps}
57 width="match_parent"
58 height="20px"
59 justifyContent="center"
60 ref={this.ref}
61 fontSize="14px"
62 >
63 {loading &&
64 <FlexRowContainer
65 width="wrap_content"
66 height="wrap_content"
67 fontSize="13px"
68 >
69 <scmp.Span
70 width="wrap_content"
71 height="wrap_content"
72 fontSize="13px"
73 >
74 {loadingText || 'loading'}
75 </scmp.Span>
76 {loadingIon || <DotLoading />}
77 </FlexRowContainer>}
78 {finish &&
79 <scmp.Span
80 width="wrap_content"
81 height="wrap_content"
82 fontSize="12px"
83 >
84 --- There are no more goods ---
85 </scmp.Span>}
86 </FlexRowContainer>
87 );
88 }
89