-
Notifications
You must be signed in to change notification settings - Fork 99
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 5, 2023
1 parent
4abc097
commit 8c18c7e
Showing
9 changed files
with
274 additions
and
19 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# PullToRefresh 下拉刷新 | ||
|
||
### 介绍 | ||
|
||
在列表中通过手指下拉刷新加载新内容的交互操作。 | ||
|
||
### 引用 | ||
|
||
```js | ||
import { PullToRefresh } from '@antmjs/vantui' | ||
``` | ||
|
||
### 基本使用 | ||
|
||
```jsx | ||
function Demo() { | ||
const onRefresh = () => { | ||
return new Promise((resolve) => { | ||
setTimeout(() => { | ||
resolve() | ||
}, 1000) | ||
}) | ||
} | ||
|
||
return ( | ||
<PullToRefresh onRefresh={onRefresh}> | ||
<View style={{ padding: '0 12px' }}> | ||
{new Array(10).fill(1).map((item, index) => ( | ||
<View | ||
style={{ padding: 12, background: '#fff', marginBottom: 12 }} | ||
key={`PullToRefresh${index}`} | ||
> | ||
{index} | ||
</View> | ||
))} | ||
</View> | ||
</PullToRefresh> | ||
) | ||
} | ||
``` |
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,11 @@ | ||
.van-pull-to-refresh { | ||
&-status { | ||
color: #969799; | ||
font-size: 28px; | ||
overflow: hidden; | ||
transition: 0.6s all; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
} | ||
} |
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 PullToRefresh from './pull-to-refresh' | ||
|
||
export default PullToRefresh | ||
|
||
export { PullToRefresh } |
148 changes: 148 additions & 0 deletions
148
packages/vantui/src/pull-to-refresh/pull-to-refresh.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,148 @@ | ||
import { useState, useCallback, useEffect, useMemo } from 'react' | ||
import { View } from '@tarojs/components' | ||
import { Loading } from '../loading' | ||
import { getRect } from '../common/utils' | ||
|
||
const clsPrefix = 'van-pull-to-refresh' | ||
|
||
type IPullToFreshProps = { | ||
children?: React.ReactNode | ||
pullText?: React.ReactNode | ||
releaseText?: React.ReactNode | ||
loadingText?: React.ReactNode | ||
renderLoading?: React.ReactNode | ||
successText?: React.ReactNode | ||
onRefresh: () => Promise<undefined> | ||
touchMaxStart: number | ||
headHeight?: number | ||
} | ||
|
||
type IStatus = 'pull' | 'release' | 'loading' | 'success' | ||
let initIndex = 0 | ||
|
||
export default function PullToRefresh(props: IPullToFreshProps) { | ||
const { | ||
children, | ||
loadingText = '加载中...', | ||
successText = '刷新成功', | ||
pullText = '下拉刷新', | ||
releaseText = '松开刷新', | ||
headHeight = 40, | ||
renderLoading, | ||
onRefresh, | ||
touchMaxStart = 300, | ||
} = props | ||
const [statusHeight, setStatusHeight] = useState(0) | ||
const [status, setStatus] = useState<IStatus>('pull') | ||
const [componentIndex] = useState(initIndex++) | ||
const [touch] = useState({ | ||
start: 0, | ||
time: 0, | ||
maxStart: 0, | ||
}) | ||
|
||
const reset = useCallback(() => { | ||
touch.start = 0 | ||
touch.time = 0 | ||
setStatusHeight(0) | ||
}, [touch]) | ||
|
||
const onTouchStart = useCallback( | ||
function (event) { | ||
if (status !== 'pull') setStatus('pull') | ||
const start = event.touches[0].clientY | ||
if (start < touch.maxStart) { | ||
touch.start = event.touches[0].clientY | ||
touch.time = Date.now() | ||
} else { | ||
touch.time = Date.now() + 9999 * 1000 | ||
} | ||
}, | ||
[status, touch], | ||
) | ||
|
||
const onTouchMove = useCallback( | ||
function (event) { | ||
if (status === 'pull' && Date.now() - touch.time > 500) { | ||
event.preventDefault() | ||
event.stopPropagation() | ||
const y = event.touches[0].clientY - touch.start | ||
setStatusHeight(y) | ||
} | ||
}, | ||
[status, touch.start, touch.time], | ||
) | ||
|
||
const onTouchEnd = useCallback(async () => { | ||
if (statusHeight > headHeight) { | ||
setStatus('loading') | ||
setStatusHeight(headHeight) | ||
if (status === 'release') { | ||
await onRefresh() | ||
setStatus('success') | ||
setTimeout(() => { | ||
reset() | ||
}, 1000) | ||
} | ||
} else { | ||
setStatusHeight(0) | ||
} | ||
}, [headHeight, onRefresh, reset, status, statusHeight]) | ||
|
||
useEffect(() => { | ||
if (status === 'pull' && statusHeight - headHeight >= 50) { | ||
setStatus('release') | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [statusHeight]) | ||
|
||
useEffect(() => { | ||
setTimeout(() => { | ||
getRect(null, `.${clsPrefix}-status${componentIndex}`).then( | ||
(res: any) => { | ||
touch.maxStart = res.top + touchMaxStart | ||
}, | ||
) | ||
}, 100) | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []) | ||
|
||
const renderHeight = useMemo(() => { | ||
return statusHeight > headHeight ? headHeight : statusHeight | ||
}, [headHeight, statusHeight]) | ||
|
||
const renderMarginBottom = useMemo(() => { | ||
let marginBottom = 0 | ||
const ly = statusHeight - headHeight | ||
if (ly > 20) { | ||
marginBottom = 20 | ||
} | ||
|
||
return marginBottom | ||
}, [headHeight, statusHeight]) | ||
|
||
return ( | ||
<View | ||
onTouchStart={onTouchStart} | ||
onTouchMove={onTouchMove} | ||
onTouchEnd={onTouchEnd} | ||
className={`${clsPrefix}`} | ||
> | ||
<View | ||
className={`${clsPrefix}-status ${clsPrefix}-status${componentIndex}`} | ||
style={{ | ||
height: renderHeight, | ||
marginBottom: renderMarginBottom, | ||
}} | ||
> | ||
{status === 'loading' && ( | ||
<>{renderLoading || <Loading size={24}>{loadingText}</Loading>}</> | ||
)} | ||
{status === 'release' && releaseText} | ||
{status === 'pull' && pullText} | ||
{status === 'success' && successText} | ||
</View> | ||
{children} | ||
</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