Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(backtop & menu): lint, code simplification, deprecated pageYOffset removed #2633

Merged
merged 8 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions src/packages/backtop/__test__/backtop.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,19 @@ import BackTop from '@/packages/backtop'
test('backtop props test', () => {
const handleClick = vi.fn()
const { container } = render(
<BackTop
target="target"
threshold={200}
style={{
right: '20px',
bottom: '50px',
}}
onClick={handleClick}
/>
<div id="target" style={{ height: '100vh' }}>
{new Array(24).fill(0).map((_, index) => {
return <div key={index}>我是测试数据{index}</div>
})}
<BackTop
target="target"
className="backtop-button"
onClick={handleClick}
/>
</div>
)
expect(container.querySelector('.nut-backtop')).toHaveAttribute(
'style',
'z-index: 900; right: 20px; bottom: 50px;'
)
fireEvent.click(container)
const chooseTagEle = container.querySelectorAll('.backtop-button')[0]
fireEvent.click(chooseTagEle)
expect(handleClick).toBeCalled
})

Expand Down
38 changes: 12 additions & 26 deletions src/packages/backtop/backtop.taro.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FunctionComponent, useState } from 'react'
import React, { FunctionComponent, useState, useCallback } from 'react'
import type { MouseEvent } from 'react'
import { usePageScroll, pageScrollTo } from '@tarojs/taro'
import { Top } from '@nutui/icons-react-taro'
Expand Down Expand Up @@ -28,26 +28,25 @@ export const BackTop: FunctionComponent<
...defaultProps,
...props,
}

const classPrefix = 'nut-backtop'

const [backTop, SetBackTop] = useState(false)

const [backTop, setBackTop] = useState(false)
const cls = classNames(classPrefix, { show: backTop }, className)
// 监听用户滑动页面事件
usePageScroll((res) => {
const { scrollTop } = res
scrollTop >= threshold ? SetBackTop(true) : SetBackTop(false)
})

// 返回顶部点击事件
const handleScroll = useCallback(
(res: { scrollTop: number }) => {
const { scrollTop } = res
setBackTop(scrollTop >= threshold)
},
[threshold]
)
usePageScroll(handleScroll)
const goTop = (e: MouseEvent<HTMLDivElement>) => {
onClick && onClick(e)
pageScrollTo({
scrollTop: 0,
duration: duration > 0 ? duration : 0,
})
}

const styles =
Object.keys(style || {}).length !== 0
? {
Expand All @@ -59,21 +58,8 @@ export const BackTop: FunctionComponent<
bottom: '20px',
zIndex,
}

return (
<div
className={classNames(
classPrefix,
{
show: backTop,
},
className
)}
style={styles}
onClick={(e) => {
goTop(e)
}}
>
<div className={cls} style={styles} onClick={(e) => goTop(e)}>
{children || <Top size={19} className="nut-backtop-main" />}
</div>
)
Expand Down
91 changes: 36 additions & 55 deletions src/packages/backtop/backtop.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import React, { FunctionComponent, useEffect, useState, useRef } from 'react'
import React, {
FunctionComponent,
useEffect,
useState,
useRef,
useCallback,
} from 'react'
import type { MouseEvent } from 'react'
import { Top } from '@nutui/icons-react'
import classNames from 'classnames'
import { BasicComponent, ComponentDefaults } from '@/utils/typings'
import requestAniFrame from '@/utils/raf'
import requestAniFrame, { cancelRaf } from '@/utils/raf'
import { useRtl } from '@/packages/configprovider'

declare const window: any

export interface BackTopProps extends BasicComponent {
target: string
threshold: number
Expand Down Expand Up @@ -46,33 +50,37 @@ export const BackTop: FunctionComponent<
const [backTop, SetBackTop] = useState(false)
const [scrollTop, SetScrollTop] = useState(0)
let startTime = 0
const scrollEl: any = useRef<any>(null)
useEffect(() => {
init()
return () => removeEventListener()
}, [])
const scrollEl = useRef<any>(null)
const cls = classNames(classPrefix, { show: backTop }, className)

const scrollListener = useCallback(() => {
let top = null
if (scrollEl.current instanceof Window) {
top = scrollEl.current.scrollY
} else {
top = scrollEl.current?.scrollTop
}
SetScrollTop(top)
SetBackTop(top >= threshold)
}, [threshold])

const init = () => {
const init = useCallback(() => {
if (target && document.getElementById(target)) {
scrollEl.current = document.getElementById(target) as HTMLElement | Window
scrollEl.current = document.getElementById(target)
} else {
scrollEl.current = window
}
addEventListener()
initCancelAniFrame()
}
const scrollListener = () => {
let top: any = null
if (scrollEl.current instanceof Window) {
top = scrollEl.current.pageYOffset
SetScrollTop(top)
} else {
top = scrollEl.current.scrollTop
SetScrollTop(top)
scrollEl.current?.addEventListener('scroll', scrollListener, false)
scrollEl.current?.addEventListener('resize', scrollListener, false)
}, [target, scrollListener])

useEffect(() => {
init()
return () => {
scrollEl.current?.removeEventListener('scroll', scrollListener, false)
scrollEl.current?.removeEventListener('resize', scrollListener, false)
}
const showBtn = top >= threshold
SetBackTop(showBtn)
}
}, [init, scrollListener])

const scroll = (y = 0) => {
if (scrollEl.current instanceof Window) {
Expand All @@ -90,29 +98,14 @@ export const BackTop: FunctionComponent<
scroll(y)
cid = requestAniFrame(fn)
if (t === duration || y === 0) {
window.cancelAnimationFrame(cid)
cancelRaf(cid)
}
})
}

const initCancelAniFrame = () => {
window.cancelAnimationFrame = window.webkitCancelAnimationFrame
}

function addEventListener() {
scrollEl.current?.addEventListener('scroll', scrollListener, false)
scrollEl.current?.addEventListener('resize', scrollListener, false)
}

function removeEventListener() {
scrollEl.current?.removeEventListener('scroll', scrollListener, false)
scrollEl.current?.removeEventListener('resize', scrollListener, false)
}

const goTop = (e: MouseEvent<HTMLDivElement>) => {
onClick && onClick(e)
const otime = +new Date()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

建议使用可选链调用onClick函数。

可以将onClick && onClick(e)替换为onClick?.(e),使代码更简洁。

应用以下修改:

-    onClick && onClick(e)
+    onClick?.(e)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onClick && onClick(e)
onClick?.(e)
🧰 Tools
🪛 Biome

[error] 107-107: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

startTime = otime
startTime = +new Date()
duration > 0 ? scrollAnimation() : scroll()
}

Expand All @@ -129,19 +122,7 @@ export const BackTop: FunctionComponent<
}

return (
<div
className={classNames(
classPrefix,
{
show: backTop,
},
className
)}
style={styles}
onClick={(e) => {
goTop(e)
}}
>
<div className={cls} style={styles} onClick={(e) => goTop(e)}>
{children || <Top width={19} height={19} className="nut-backtop-main" />}
</div>
)
Expand Down
97 changes: 97 additions & 0 deletions src/packages/menu/__test__/__snapshots__/menu.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,100 @@ exports[`should match snapshot 1`] = `
</div>
</DocumentFragment>
`;

exports[`should match snapshot of two columns in one line 1`] = `
<DocumentFragment>
<div
class="nut-menu"
>
<div
class="nut-menu-bar"
>
<div
class="nut-menu-title nut-menu-title-0"
>
<div
class="nut-menu-title-text"
>
全部商品
</div>
<svg
aria-labelledby="ArrowDown"
class="nut-icon nut-icon-ArrowDown nut-menu-title-icon"
role="presentation"
style="width: 12px; height: 12px;"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M158.17 289.83a42.67 42.67 0 1 0-60.34 60.34l384 384a42.67 42.67 0 0 0 60.36 0l384-384a42.67 42.67 0 1 0-60.36-60.34L512 643.67z"
fill="currentColor"
fill-opacity="0.9"
/>
</svg>
</div>
</div>
<div
class="nut-menu-container"
>
<div
class="nut-menu-container-wrap"
style="display: none;"
>
<div
class="nut-menu-container-content"
>
<div
class="nut-menu-container-item active"
style="flex-basis: 50%;"
>
<i
class="nut-menu-container-item-icon"
>
<svg
aria-labelledby="Check"
class="nut-icon nut-icon-Check "
color=""
role="presentation"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M998.4 245.03c-219.43 153.6-398.63 332.8-552.23 552.23-40.23 58.51-128 54.86-164.57-3.66-69.49-106.06-149.94-186.51-256-256-51.2-32.91-18.29-113.37 40.23-98.74 117.03 21.94 208.46 69.49 292.57 146.28 157.26-190.17 358.4-340.11 588.8-435.2 62.17-25.6 106.06 58.51 51.2 95.09"
fill="currentColor"
fill-opacity="0.9"
/>
</svg>
</i>
<div
class="nut-menu-container-item-title "
>
全部商品
</div>
</div>
<div
class="nut-menu-container-item "
style="flex-basis: 50%;"
>
<div
class="nut-menu-container-item-title "
>
新款商品
</div>
</div>
<div
class="nut-menu-container-item "
style="flex-basis: 50%;"
>
<div
class="nut-menu-container-item-title "
>
活动商品
</div>
</div>
</div>
</div>
</div>
</div>
</DocumentFragment>
`;
Loading
Loading