-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
kongjing
committed
Mar 4, 2023
1 parent
33e8853
commit 4abc097
Showing
10 changed files
with
358 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# InfiniteScroll 无限滚动 | ||
|
||
### 介绍 | ||
|
||
InfiniteScroll 组件在可见区域时自动加载更多数据。 | ||
|
||
### 引入 | ||
|
||
在 Taro 文件中引入组件 | ||
|
||
```js | ||
import { InfiniteScroll } from '@antmjs/vantui' | ||
``` | ||
|
||
### 基本使用 | ||
|
||
- 可见区域为窗口,如果滚动区域不是窗体则通过`parentClassName`设置父元素类名 | ||
|
||
```jsx | ||
function Demo() { | ||
const [data, setdata] = react.useState([]) | ||
const mockRequest = COMMON.mockRequest | ||
|
||
const loadMore = async () => { | ||
return new Promise(async (resolve) => { | ||
const reslult = await mockRequest() | ||
const newData = [].concat(data, reslult) | ||
setdata(newData) | ||
// 以下是简单的模拟请求,正常请求请按条件执行`resolve('complete')` | ||
resolve(newData.length > 60 ? 'complete' : 'loading') | ||
}) | ||
} | ||
|
||
return ( | ||
<View style={{ padding: '4px 6px' }} onClick={loadMore}> | ||
{data.map((item, index) => ( | ||
<View | ||
style={{ padding: '12px 6px', borderBottom: '1px solid #eee' }} | ||
key={item} | ||
> | ||
<Text className="dataIndex">Index{index + 1}</Text> | ||
{item} | ||
</View> | ||
))} | ||
<InfiniteScroll loadMore={loadMore} /> | ||
</View> | ||
) | ||
} | ||
``` | ||
|
||
模拟获取数据 | ||
|
||
```js common | ||
const mockRequest = () => { | ||
return new Promise((resolve) => { | ||
setTimeout(() => { | ||
resolve(new Array(20).fill('').map((item) => `数据:${Math.random()}`)) | ||
}, 1500) | ||
}) | ||
} | ||
``` | ||
|
||
### 请求异常 | ||
|
||
```jsx | ||
function Demo() { | ||
const [data, setdata] = react.useState([]) | ||
const mockRequest = COMMON.mockRequest | ||
|
||
const loadMore = async () => { | ||
return new Promise(async (resolve) => { | ||
const reslult = await mockRequest() | ||
const newData = [].concat(data, reslult) | ||
setdata(newData) | ||
// 以下是简单的模拟请求,正常请求请按条件执行`resolve('error')` | ||
resolve(Math.random() > 0.3 ? 'error' : 'loading') | ||
}) | ||
} | ||
|
||
return ( | ||
<View style={{ padding: '4px 6px' }}> | ||
{data.map((item, index) => ( | ||
<View | ||
style={{ padding: '12px 6px', borderBottom: '1px solid #eee' }} | ||
key={item} | ||
> | ||
<Text className="dataIndex">Index{index + 1}</Text> | ||
{item} | ||
</View> | ||
))} | ||
<InfiniteScroll loadMore={loadMore} /> | ||
</View> | ||
) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
@import '../style/var.less'; | ||
|
||
.van-infinite-scroll { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
|
||
&-loading, | ||
&-complete, | ||
&-error { | ||
color: @infinite-scroll-color; | ||
font-size: @infinite-scroll-font-size; | ||
line-height: 40px; | ||
padding: 24px 0; | ||
} | ||
|
||
&-error { | ||
.reload-btn { | ||
padding-left: 8px; | ||
color: @infinite-scroll-primary-color; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { InfiniteScroll } from './infinite-scroll' | ||
|
||
export { InfiniteScroll } | ||
|
||
export default InfiniteScroll |
158 changes: 158 additions & 0 deletions
158
packages/vantui/src/infinite-scroll/infinite-scroll.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import { getCurrentPages, createIntersectionObserver } from '@tarojs/taro' | ||
import { View, Text } from '@tarojs/components' | ||
import { useState, useCallback, useRef, useEffect } from 'react' | ||
import { Loading } from '../loading' | ||
import { InfiniteScrollProps } from '../../types/index' | ||
|
||
const clsPrefix = `van-infinite-scroll` | ||
type IStatus = 'loading' | 'complete' | 'error' | ||
let compInitIndex = 0 | ||
|
||
export function InfiniteScroll(props: InfiniteScrollProps) { | ||
const { | ||
renderLoading, | ||
renderComplete, | ||
renderError, | ||
parentClassName, | ||
loadMore, | ||
className = '', | ||
completeText = '没有更多了~', | ||
loadingText = '加载中...', | ||
errorText = '加载失败', | ||
reloadText = '重新加载', | ||
} = props | ||
const [status, setStatus] = useState<IStatus>('loading') | ||
const [onRequest, setOnRequest] = useState(false) | ||
const contentObserver = useRef<any>() | ||
const [compIndex] = useState(compInitIndex++) | ||
const thisDom = useRef() | ||
const [forceKey, setForceKey] = useState(0) // 解决IntersectionObserver中执行loadmore时无法拿到最新的俩是state | ||
|
||
const reset = useCallback(() => { | ||
setForceKey(0) | ||
setStatus('loading') | ||
setOnRequest(false) | ||
}, []) | ||
|
||
const _loadMore = useCallback( | ||
async (immediately?: boolean) => { | ||
if ((!onRequest && status === 'loading') || immediately) { | ||
setOnRequest(true) | ||
const status = await loadMore() | ||
setStatus(status) | ||
setOnRequest(false) | ||
} | ||
}, | ||
[loadMore, onRequest, status], | ||
) | ||
|
||
useEffect(() => { | ||
return () => { | ||
reset() | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []) | ||
|
||
useEffect(() => { | ||
if (forceKey !== 0) _loadMore() | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [forceKey]) | ||
|
||
const initObserveH5 = useCallback(() => { | ||
const options: any = { | ||
threshold: [0.6], | ||
} | ||
if (parentClassName) | ||
options.root = document.getElementsByClassName(parentClassName)[0] | ||
const contentObserver_ = new IntersectionObserver(function (res: any) { | ||
const target = res[0] | ||
if (target && target.intersectionRatio > 0.6) { | ||
setForceKey(Math.random() + Math.random()) | ||
} | ||
}, options) | ||
contentObserver.current = contentObserver_ | ||
contentObserver.current.observe(thisDom.current) | ||
}, [parentClassName]) | ||
|
||
const initObserve = useCallback( | ||
function () { | ||
if (contentObserver.current != null) { | ||
contentObserver.current.disconnect() | ||
} | ||
if (process.env.TARO_ENV === 'h5') { | ||
return initObserveH5() | ||
} | ||
const pages: any = getCurrentPages() | ||
const curePage = pages[pages.length - 1] | ||
let _createIntersectionObserver = curePage.createIntersectionObserver | ||
|
||
if (process.env.TARO_ENV === 'alipay') { | ||
_createIntersectionObserver = createIntersectionObserver | ||
} | ||
|
||
const contentObserver_ = _createIntersectionObserver({ | ||
thresholds: [1], | ||
}) | ||
contentObserver.current = contentObserver_ | ||
if (parentClassName) { | ||
contentObserver.current.relativeTo(parentClassName) | ||
} else { | ||
contentObserver.current.relativeToViewport({ bottom: 0 }) | ||
} | ||
contentObserver.current.observe(`.${clsPrefix}${compIndex}`, () => { | ||
setForceKey(Math.random() + Math.random()) | ||
}) | ||
}, | ||
[compIndex, initObserveH5, parentClassName], | ||
) | ||
|
||
useEffect(() => { | ||
setTimeout(() => { | ||
initObserve() | ||
}, 33) | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []) | ||
|
||
const retry = useCallback(() => { | ||
reset() | ||
_loadMore(true) | ||
}, [_loadMore, reset]) | ||
|
||
return ( | ||
<View | ||
className={`${clsPrefix} ${clsPrefix}${compIndex} ${className}`} | ||
ref={thisDom} | ||
> | ||
{status === 'loading' && ( | ||
<> | ||
{renderLoading || ( | ||
<Loading size={24} className={`${clsPrefix}-loading`}> | ||
{loadingText} | ||
</Loading> | ||
)} | ||
</> | ||
)} | ||
{status === 'complete' && ( | ||
<> | ||
{renderComplete || ( | ||
<View className={`${clsPrefix}-complete`}>{completeText}</View> | ||
)} | ||
</> | ||
)} | ||
{status === 'error' && ( | ||
<> | ||
{renderError || ( | ||
<View className={`${clsPrefix}-error`}> | ||
<Text>{errorText}</Text> | ||
<Text className="reload-btn" onClick={retry}> | ||
{reloadText} | ||
</Text> | ||
</View> | ||
)} | ||
</> | ||
)} | ||
</View> | ||
) | ||
} | ||
|
||
export default InfiniteScroll |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.