-
Notifications
You must be signed in to change notification settings - Fork 285
fix(backtop & menu): lint, code simplification, deprecated pageYOffset removed #2633
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
Changes from 3 commits
6ddcc8b
9744ce0
98fa2c7
e995cb6
11b9288
b497d1d
bb1d254
693adb6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||||||
|
|
@@ -46,33 +50,37 @@ | |||||
| 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) { | ||||||
|
|
@@ -90,29 +98,14 @@ | |||||
| 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) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 建议使用可选链调用 可以将 应用以下修改: - onClick && onClick(e)
+ onClick?.(e)📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome
|
||||||
| const otime = +new Date() | ||||||
| startTime = otime | ||||||
| startTime = +new Date() | ||||||
| duration > 0 ? scrollAnimation() : scroll() | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -129,19 +122,7 @@ | |||||
| } | ||||||
|
|
||||||
| 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> | ||||||
| ) | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,10 @@ | ||
| import React, { FunctionComponent, useEffect, useRef, useState } from 'react' | ||
| import React, { | ||
| FunctionComponent, | ||
| useCallback, | ||
| useEffect, | ||
| useRef, | ||
| useState, | ||
| } from 'react' | ||
| import classNames from 'classnames' | ||
| import { ArrowDown, ArrowUp } from '@nutui/icons-react-taro' | ||
| import { OptionItem, MenuItem } from '@/packages/menuitem/menuitem.taro' | ||
|
|
@@ -53,29 +59,30 @@ export const Menu: FunctionComponent<Partial<MenuProps>> & { | |
| ...props, | ||
| } | ||
| const menuRef = useRef(null) | ||
| const [showMenuItem, setShowMenuItem] = useState<boolean[]>([]) | ||
| const [menuItemTitle, setMenuItemTitle] = useState<string[]>([]) | ||
| const [isScrollFixed, setIsScrollFixed] = useState(false) | ||
| const cls = classNames(`nut-menu`, className, { | ||
| 'scroll-fixed': isScrollFixed, | ||
| }) | ||
|
|
||
| const getScrollTop = (el: Element | Window) => { | ||
| return Math.max(0, 'scrollTop' in el ? el.scrollTop : el.pageYOffset) | ||
| return Math.max(0, 'scrollTop' in el ? el.scrollTop : el.scrollY) | ||
|
||
| } | ||
| const onScroll = () => { | ||
| const { scrollFixed } = props | ||
|
|
||
| const onScroll = useCallback(() => { | ||
| const scrollTop = getScrollTop(window) | ||
| const isFixed = | ||
| scrollTop > (typeof scrollFixed === 'boolean' ? 30 : Number(scrollFixed)) | ||
| setIsScrollFixed(isFixed) | ||
| } | ||
| }, [scrollFixed]) | ||
|
|
||
| useEffect(() => { | ||
| if (scrollFixed) { | ||
| window.addEventListener('scroll', onScroll) | ||
| } | ||
| return () => window.removeEventListener('scroll', onScroll) | ||
| }, []) | ||
| }, [scrollFixed, onScroll]) | ||
|
|
||
| const [showMenuItem, setShowMenuItem] = useState<boolean[]>([]) | ||
| const [menuItemTitle, setMenuItemTitle] = useState<string[]>([]) | ||
| const toggleMenuItem: MenuCallBackFunction = (index, from = 'NORMAL') => { | ||
| showMenuItem[index] = !showMenuItem[index] | ||
| if (showMenuItem[index]) { | ||
|
|
@@ -97,7 +104,6 @@ export const Menu: FunctionComponent<Partial<MenuProps>> & { | |
| menuItemTitle[index] = text | ||
| setMenuItemTitle([...menuItemTitle]) | ||
| } | ||
|
|
||
| const cloneChildren = () => { | ||
| return React.Children.map(children, (child, index) => { | ||
| return React.cloneElement(child as any, { | ||
|
|
@@ -179,13 +185,7 @@ export const Menu: FunctionComponent<Partial<MenuProps>> & { | |
| }) | ||
| } | ||
| return ( | ||
| <div | ||
| {...rest} | ||
| className={classNames(`nut-menu`, className, { | ||
| 'scroll-fixed': isScrollFixed, | ||
| })} | ||
| ref={menuRef} | ||
| > | ||
| <div {...rest} className={cls} ref={menuRef}> | ||
| <div | ||
| className={classNames('nut-menu-bar', { | ||
| opened: showMenuItem.includes(true), | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,10 @@ | ||||||||||||||||||||||||||||||||||||
| import React, { FunctionComponent, useEffect, useRef, useState } from 'react' | ||||||||||||||||||||||||||||||||||||
| import React, { | ||||||||||||||||||||||||||||||||||||
| FunctionComponent, | ||||||||||||||||||||||||||||||||||||
| useCallback, | ||||||||||||||||||||||||||||||||||||
| useEffect, | ||||||||||||||||||||||||||||||||||||
| useRef, | ||||||||||||||||||||||||||||||||||||
| useState, | ||||||||||||||||||||||||||||||||||||
| } from 'react' | ||||||||||||||||||||||||||||||||||||
| import classNames from 'classnames' | ||||||||||||||||||||||||||||||||||||
| import { ArrowDown, ArrowUp } from '@nutui/icons-react' | ||||||||||||||||||||||||||||||||||||
| import { OptionItem, MenuItem } from '@/packages/menuitem/menuitem' | ||||||||||||||||||||||||||||||||||||
|
|
@@ -53,29 +59,30 @@ | |||||||||||||||||||||||||||||||||||
| ...props, | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| const menuRef = useRef(null) | ||||||||||||||||||||||||||||||||||||
| const [showMenuItem, setShowMenuItem] = useState<boolean[]>([]) | ||||||||||||||||||||||||||||||||||||
| const [menuItemTitle, setMenuItemTitle] = useState<string[]>([]) | ||||||||||||||||||||||||||||||||||||
| const [isScrollFixed, setIsScrollFixed] = useState(false) | ||||||||||||||||||||||||||||||||||||
| const cls = classNames(`nut-menu`, className, { | ||||||||||||||||||||||||||||||||||||
| 'scroll-fixed': isScrollFixed, | ||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const getScrollTop = (el: Element | Window) => { | ||||||||||||||||||||||||||||||||||||
| return Math.max(0, 'scrollTop' in el ? el.scrollTop : el.pageYOffset) | ||||||||||||||||||||||||||||||||||||
| return Math.max(0, 'scrollTop' in el ? el.scrollTop : el.scrollY) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| const onScroll = () => { | ||||||||||||||||||||||||||||||||||||
| const { scrollFixed } = props | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const onScroll = useCallback(() => { | ||||||||||||||||||||||||||||||||||||
| const scrollTop = getScrollTop(window) | ||||||||||||||||||||||||||||||||||||
| const isFixed = | ||||||||||||||||||||||||||||||||||||
| scrollTop > (typeof scrollFixed === 'boolean' ? 30 : Number(scrollFixed)) | ||||||||||||||||||||||||||||||||||||
| setIsScrollFixed(isFixed) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| }, [scrollFixed]) | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+75
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 确保 在 建议在使用前添加类型检查和默认值,例如: const isFixed =
- scrollTop > (typeof scrollFixed === 'boolean' ? 30 : Number(scrollFixed))
+ scrollTop > (typeof scrollFixed === 'boolean'
+ ? 30
+ : !isNaN(Number(scrollFixed))
+ ? Number(scrollFixed)
+ : 30)📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||
| if (scrollFixed) { | ||||||||||||||||||||||||||||||||||||
| window.addEventListener('scroll', onScroll) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| return () => window.removeEventListener('scroll', onScroll) | ||||||||||||||||||||||||||||||||||||
| }, []) | ||||||||||||||||||||||||||||||||||||
| }, [scrollFixed, onScroll]) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const [showMenuItem, setShowMenuItem] = useState<boolean[]>([]) | ||||||||||||||||||||||||||||||||||||
| const [menuItemTitle, setMenuItemTitle] = useState<string[]>([]) | ||||||||||||||||||||||||||||||||||||
| const toggleMenuItem: MenuCallBackFunction = (index, from = 'NORMAL') => { | ||||||||||||||||||||||||||||||||||||
| showMenuItem[index] = !showMenuItem[index] | ||||||||||||||||||||||||||||||||||||
| if (showMenuItem[index]) { | ||||||||||||||||||||||||||||||||||||
|
|
@@ -180,13 +187,7 @@ | |||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||
| {...rest} | ||||||||||||||||||||||||||||||||||||
| className={classNames(`nut-menu`, className, { | ||||||||||||||||||||||||||||||||||||
| 'scroll-fixed': isScrollFixed, | ||||||||||||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||||||||||||
| ref={menuRef} | ||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||
| <div {...rest} className={cls} ref={menuRef}> | ||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 合并 在第193行, 您可以按以下方式修改代码: - <div {...rest} className={cls} ref={menuRef}>
+ <div {...rest} className={classNames(cls, rest.className)} ref={menuRef}>📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||
| className={classNames('nut-menu-bar', { | ||||||||||||||||||||||||||||||||||||
| opened: showMenuItem.includes(true), | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
性能优化建议
建议使用
useCallback钩子来优化滚动处理函数,特别是当threshold可能经常变化时。这可以防止不必要的重新渲染。例如:这样可以确保只有当
threshold发生变化时,才会创建新的滚动处理函数。