Skip to content

Commit 42b3e53

Browse files
feat(Backtop): refactor backtop using hoverbutton and v15 adaption (#2866)
* refactor: use hoverbutton * fix: 鸿蒙下露出 * test: fixed * test: add tests * feat: 支持 icon * fix: lint ts * test: update case --------- Co-authored-by: oasis <suanbanren@foxmail.com>
1 parent 8d41a63 commit 42b3e53

File tree

22 files changed

+172
-313
lines changed

22 files changed

+172
-313
lines changed

migrate-from-v2.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -562,10 +562,9 @@ plugins: [
562562

563563
#### BackTop
564564

565-
- `elId` 重命名为 `target`
566-
- 移除 `right``bottom`,通过 style 传入,增加支持 `left``top`
567-
- `distance` 重命名为 `threshold`
568-
- 移除 `isAnimation`,通过 `duration` 设置 0 实现无动画效果
565+
- 使用 `HoverButton` 重构 `BackTop`
566+
- 新增 `icon` 字段,可直接修改图标
567+
- 继续支持自定义节点
569568

570569
#### Dialog
571570

src/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@
274274
"tarodoc": true,
275275
"show": true,
276276
"taro": true,
277+
"v15": true,
277278
"author": "vickyYe"
278279
},
279280
{

src/packages/backtop/__test__/__snapshots__/backtop.spec.tsx.snap

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,38 @@
33
exports[`backtop custom test 1`] = `
44
<div>
55
<div
6-
class="nut-backtop custom-class"
6+
class="nut-hoverbutton-container nut-backtop custom-class"
77
style="z-index: 900; bottom: 110px; right: 10px;"
88
>
99
<div
10-
class="backtop-demo"
11-
style="display: flex; flex-direction: column; align-items: center;"
10+
class="nut-hoverbutton"
1211
>
13-
<svg
14-
aria-labelledby="Top"
15-
class="nut-icon nut-icon-Top nut-backtop-main"
16-
role="presentation"
17-
style="width: 12px; height: 12px;"
18-
viewBox="0 0 1024 1024"
19-
xmlns="http://www.w3.org/2000/svg"
20-
>
21-
<path
22-
d="M128 0a42.67 42.67 0 1 0 0 85.33h768A42.67 42.67 0 1 0 896 0zm391.21 173.42a10.88 10.88 0 0 0-14.42 0L3.61 619.67a10.71 10.71 0 0 0 7.21 18.67h241.34v257.11c0 71 58.05 128.55 129.64 128.55h260.4c71.59 0 129.64-57.56 129.64-128.55V638.34h241.34a10.71 10.71 0 0 0 7.21-18.67zM338.6 895.45V552.64H208.21L512 282.15l303.77 270.49H685.42v342.83c0 23.64-19.37 42.84-43.22 42.83H381.8c-23.85 0-43.2-19.2-43.2-42.85"
23-
fill="currentColor"
24-
fill-opacity="0.9"
25-
/>
26-
</svg>
2712
<div
28-
style="font-size: 12px;"
13+
class="nut-hoverbutton-item-container"
2914
>
30-
顶部
15+
<svg
16+
aria-labelledby="Top"
17+
class="nut-icon nut-icon-Top "
18+
role="presentation"
19+
viewBox="0 0 1024 1024"
20+
xmlns="http://www.w3.org/2000/svg"
21+
>
22+
<path
23+
d="M128 0a42.67 42.67 0 1 0 0 85.33h768A42.67 42.67 0 1 0 896 0zm391.21 173.42a10.88 10.88 0 0 0-14.42 0L3.61 619.67a10.71 10.71 0 0 0 7.21 18.67h241.34v257.11c0 71 58.05 128.55 129.64 128.55h260.4c71.59 0 129.64-57.56 129.64-128.55V638.34h241.34a10.71 10.71 0 0 0 7.21-18.67zM338.6 895.45V552.64H208.21L512 282.15l303.77 270.49H685.42v342.83c0 23.64-19.37 42.84-43.22 42.83H381.8c-23.85 0-43.2-19.2-43.2-42.85"
24+
fill="currentColor"
25+
fill-opacity="0.9"
26+
/>
27+
</svg>
28+
<div
29+
style="font-size: 12px;"
30+
>
31+
顶部
32+
</div>
3133
</div>
3234
</div>
35+
<div
36+
class="nut-safe-area nut-safe-area-position-bottom"
37+
/>
3338
</div>
3439
</div>
3540
`;

src/packages/backtop/__test__/backtop.spec.tsx

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import * as React from 'react'
33
import '@testing-library/jest-dom'
44
import { Top } from '@nutui/icons-react'
5-
import { render, fireEvent } from '@testing-library/react'
5+
import { act, fireEvent, render, waitFor } from '@testing-library/react'
66
import BackTop from '@/packages/backtop'
77

88
test('backtop props test', () => {
@@ -37,31 +37,46 @@ test('backtop custom test', () => {
3737
}}
3838
onClick={handleClick}
3939
>
40-
<div
41-
className="backtop-demo"
42-
style={{
43-
display: 'flex',
44-
flexDirection: 'column',
45-
alignItems: 'center',
46-
}}
47-
>
48-
<Top width="12px" height="12px" className="nut-backtop-main" />
49-
<div style={{ fontSize: '12px' }}>顶部</div>
50-
</div>
40+
<Top />
41+
<div style={{ fontSize: '12px' }}>顶部</div>
5142
</BackTop>
5243
)
5344
expect(container.querySelector('.nut-backtop')).toHaveAttribute(
5445
'style',
5546
'z-index: 900; bottom: 110px; right: 10px;'
5647
)
57-
expect(container.querySelector('.backtop-demo')).toHaveAttribute(
58-
'style',
59-
'display: flex; flex-direction: column; align-items: center;'
60-
)
61-
expect(container.querySelector('.nut-icon-Top')).toHaveClass(
62-
'nut-backtop-main'
63-
)
6448
fireEvent.click(container)
6549
expect(handleClick).toBeCalled
6650
expect(container).toMatchSnapshot()
6751
})
52+
53+
test('scroll', async () => {
54+
const { container } = render(
55+
<div id="target" style={{ height: '100px' }} className="backtop-wrapper">
56+
{new Array(24).fill(0).map((_, index) => {
57+
return (
58+
<div key={index} style={{ height: 30 }}>
59+
我是测试数据{index}
60+
</div>
61+
)
62+
})}
63+
<BackTop target="target" className="backtop-button" />
64+
</div>
65+
)
66+
const track = container.querySelector('.backtop-wrapper')
67+
const element18 = container.querySelectorAll(
68+
'.nut-hoverbutton-item-container'
69+
)[0]
70+
const element19 = container.querySelectorAll('.nut-hoverbutton-container')[0]
71+
if (track) {
72+
track.scrollTo = vi.fn()
73+
track.scrollTop = 200
74+
act(() => {
75+
track.dispatchEvent(new Event('scroll'))
76+
})
77+
await waitFor(() => {
78+
expect(element19).toHaveClass('nut-backtop-show')
79+
})
80+
fireEvent.click(element18 as Element)
81+
}
82+
})

src/packages/backtop/backtop.scss

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,22 @@
11
.nut-backtop {
22
display: none;
3-
position: fixed;
43

54
&-rn {
65
position: absolute;
76
}
87

98
&-show {
10-
width: 40px;
11-
height: 40px;
129
display: flex;
1310
align-items: center;
1411
justify-content: center;
15-
background: $color-background-overlay;
16-
color: $color-title;
17-
border: 1px solid $backtop-border-color;
18-
border-radius: 21px;
19-
z-index: 100;
20-
21-
&:active,
22-
&-active {
23-
background: $color-background;
24-
}
25-
}
26-
27-
&-main {
12+
width: $hoverbutton-item-size;
13+
height: $hoverbutton-item-size;
2814
transition: all 0.2s ease-in-out;
29-
color: $color-title;
15+
.nut-hoverbutton-item-container {
16+
display: flex;
17+
flex-direction: column;
18+
justify-content: center;
19+
align-items: center;
20+
}
3021
}
3122
}

src/packages/backtop/backtop.taro.tsx

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React, {
22
FunctionComponent,
33
useCallback,
44
useState,
5-
useMemo,
65
useEffect,
76
useRef,
87
} from 'react'
@@ -13,23 +12,24 @@ import {
1312
PageScrollObject,
1413
getSystemInfo,
1514
} from '@tarojs/taro'
16-
import { View, ITouchEvent } from '@tarojs/components'
17-
import { Top } from '@nutui/icons-react-taro'
15+
import { ITouchEvent, View } from '@tarojs/components'
1816
import classNames from 'classnames'
19-
import { BasicComponent, ComponentDefaults } from '@/utils/typings'
20-
import { useRtl } from '@/packages/configprovider/index.taro'
21-
import { harmonyAndRn, rn } from '@/utils/platform-taro'
22-
import pxTransform from '@/utils/px-transform'
17+
import { Top } from '@nutui/icons-react-taro'
18+
import { ComponentDefaults } from '@/utils/typings'
19+
import HoverButton, {
20+
HoverButtonProps,
21+
} from '@/packages/hoverbutton/index.taro'
22+
import { rn } from '@/utils/platform-taro'
2323

24-
export interface BackTopProps extends BasicComponent {
24+
export interface BackTopProps extends HoverButtonProps {
2525
threshold: number
2626
zIndex: number
2727
duration: number
2828
/**
2929
* 容器滚动时的回调参数,主要用于 rn、鸿蒙端
3030
*/
3131
scrollRes?: PageScrollObject
32-
onClick?: (event: React.MouseEvent<Element, MouseEvent> | ITouchEvent) => void
32+
onClick?: (event: React.MouseEvent<HTMLDivElement> | ITouchEvent) => void
3333
}
3434

3535
const defaultProps = {
@@ -39,18 +39,16 @@ const defaultProps = {
3939
duration: 1000,
4040
} as BackTopProps
4141

42-
const isNative = harmonyAndRn()
43-
4442
export const BackTop: FunctionComponent<
4543
Partial<BackTopProps> & Omit<React.HTMLAttributes<HTMLDivElement>, 'onClick'>
4644
> = (props) => {
47-
const rtl = useRtl()
4845
const {
4946
children,
5047
threshold,
5148
zIndex,
5249
className,
5350
duration,
51+
icon,
5452
style,
5553
scrollRes,
5654
onClick,
@@ -60,12 +58,10 @@ export const BackTop: FunctionComponent<
6058
}
6159
const classPrefix = 'nut-backtop'
6260
const [backTop, setBackTop] = useState(false)
63-
const [isTouchStart, setTouchStart] = useState(false)
6461
const cls = classNames(
6562
classPrefix,
6663
{
6764
[`${classPrefix}-show`]: backTop,
68-
[`${classPrefix}-show-active`]: isNative && isTouchStart,
6965
[`${classPrefix}-rn`]: rn(),
7066
},
7167
className
@@ -77,14 +73,6 @@ export const BackTop: FunctionComponent<
7773
})
7874
}, [])
7975

80-
const handleActiveStart = useCallback(() => {
81-
isNative && setTouchStart(true)
82-
}, [])
83-
84-
const handleActiveEnd = useCallback(() => {
85-
isNative && setTouchStart(false)
86-
}, [])
87-
8876
const onScroll = useCallback(
8977
(res: PageScrollObject) => {
9078
const { scrollTop } = res
@@ -103,7 +91,7 @@ export const BackTop: FunctionComponent<
10391

10492
// 返回顶部点击事件
10593
const goTop = useCallback(
106-
(e: React.MouseEvent<Element, MouseEvent> | ITouchEvent) => {
94+
(e: MouseEvent<HTMLDivElement> | ITouchEvent) => {
10795
onClick?.(e)
10896
pageScrollTo({
10997
scrollTop: 0,
@@ -113,32 +101,26 @@ export const BackTop: FunctionComponent<
113101
[duration, onClick]
114102
)
115103

116-
const styles = useMemo(() => {
117-
return Object.keys(style || {}).length !== 0
118-
? {
119-
zIndex,
120-
...style,
121-
}
122-
: {
123-
[rtl ? 'left' : 'right']: pxTransform(10),
124-
bottom: pxTransform(20),
125-
zIndex,
126-
}
127-
}, [rtl, style, zIndex])
128-
129104
return (
130-
<View
105+
<HoverButton
131106
className={cls}
132-
style={styles}
107+
style={{ zIndex, ...style }}
108+
icon={!children && (icon || <Top />)}
133109
onClick={(e) => {
134110
goTop(e)
135111
}}
136-
onTouchStart={handleActiveStart}
137-
onTouchEnd={handleActiveEnd}
138-
onTouchCancel={handleActiveEnd}
139112
>
140-
{children || <Top size={19} className="nut-backtop-main" />}
141-
</View>
113+
{children && (
114+
<View
115+
className="nut-hoverbutton-item-container"
116+
onClick={(e) => {
117+
goTop(e)
118+
}}
119+
>
120+
{children}
121+
</View>
122+
)}
123+
</HoverButton>
142124
)
143125
}
144126

0 commit comments

Comments
 (0)