-
Notifications
You must be signed in to change notification settings - Fork 267
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(AnimatingNumbers): 多端适配 #2700
Changes from all commits
fcd301a
0bf3823
9e33d58
844a60d
df4f024
ea6aa32
d4adac8
847c2ed
a4f2168
b127792
ddc9568
f3ddd5b
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,41 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.nut-countup-list { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
display: inline-flex; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
height: 32px; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
overflow: hidden; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
direction: ltr; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.nut-countup-listitem { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
height: 32px; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
overflow: hidden; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
user-select: none; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-webkit-tap-highlight-color: transparent; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.nut-countup-listitem-number { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
margin: 0 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
border-radius: 4px; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color: #1a1a1a; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
background-color: inherit; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.nut-countup-separator { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
display: flex; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
height: 80%; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
align-items: flex-end; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color: inherit; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
font-size: 18px; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
font-weight: 600; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.nut-countup-number { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
display: flex; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
flex-direction: column; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
align-items: center; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
width: auto; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
transition: transform 1s ease-in-out; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
transform: translate(0, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+27
to
+34
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. 🛠️ Refactor suggestion 优化动画性能 当前的动画实现可能在某些设备上出现性能问题。建议添加硬件加速和优化动画属性: .nut-countup-number {
display: flex;
flex-direction: column;
align-items: center;
width: auto;
transition: transform 1s ease-in-out;
transform: translate(0, 0);
+ will-change: transform;
+ -webkit-transform: translate3d(0, 0, 0);
+ backface-visibility: hidden;
} 📝 Committable suggestion
Suggested change
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. will-change 有可能存在布局影响,慎重考虑 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. @oasis-cloud 感谢您的提醒,的确,使用 ✏️ Learnings added
Comment on lines
+27
to
+34
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. 🛠️ Refactor suggestion 优化动画性能 考虑到之前的经验,建议通过以下方式优化动画性能: .nut-countup-number {
display: flex;
flex-direction: column;
align-items: center;
width: auto;
- transition: transform 1s ease-in-out;
+ transition: transform 1s cubic-bezier(0.23, 1, 0.32, 1);
transform: translate(0, 0);
+ transform: translate3d(0, 0, 0);
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.nut-countup-number-text { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
height: 32px; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
line-height: 32px; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color: #1a1a1a; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
font-size: 18px; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
font-weight: 600; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6,7 +6,7 @@ import React, { | |||||||||||||||||||||
useRef, | ||||||||||||||||||||||
useState, | ||||||||||||||||||||||
} from 'react' | ||||||||||||||||||||||
import { View } from '@tarojs/components' | ||||||||||||||||||||||
import { View, Text } from '@tarojs/components' | ||||||||||||||||||||||
import { createSelectorQuery } from '@tarojs/taro' | ||||||||||||||||||||||
import { BasicComponent, ComponentDefaults } from '@/utils/typings' | ||||||||||||||||||||||
import { mergeProps } from '@/utils/merge-props' | ||||||||||||||||||||||
|
@@ -39,7 +39,7 @@ export const CountUp: FunctionComponent<Partial<CountUpProps>> = (props) => { | |||||||||||||||||||||
} = mergeProps(defaultProps, props) | ||||||||||||||||||||||
const classPrefix = 'nut-countup' | ||||||||||||||||||||||
const countupRef = useRef<HTMLDivElement>(null) | ||||||||||||||||||||||
const timerRef = useRef(0) | ||||||||||||||||||||||
const timerRef = useRef() | ||||||||||||||||||||||
const numbers = Array.from({ length: 10 }, (v, i) => i) | ||||||||||||||||||||||
|
||||||||||||||||||||||
const getShowNumber = useCallback(() => { | ||||||||||||||||||||||
|
@@ -54,65 +54,66 @@ export const CountUp: FunctionComponent<Partial<CountUpProps>> = (props) => { | |||||||||||||||||||||
return currNumber.split('') | ||||||||||||||||||||||
}, [length, thousands, value]) | ||||||||||||||||||||||
|
||||||||||||||||||||||
const [numerArr, setNumerArr] = useState<string[]>([]) | ||||||||||||||||||||||
const [transformArr, setTransformArr] = useState<Array<string>>([]) | ||||||||||||||||||||||
const [numberArr, setNumberArr] = useState<string[]>([]) | ||||||||||||||||||||||
const [transformArr, setTransformArr] = useState<CSSProperties[]>([]) | ||||||||||||||||||||||
const isLoaded = useRef(false) | ||||||||||||||||||||||
|
||||||||||||||||||||||
const setNumberTransform = useCallback(() => { | ||||||||||||||||||||||
if (countupRef.current && numerArr.length) { | ||||||||||||||||||||||
if (countupRef.current && numberArr.length) { | ||||||||||||||||||||||
createSelectorQuery() | ||||||||||||||||||||||
.selectAll('.nut-countup-listitem') | ||||||||||||||||||||||
.node((numberItems: any) => { | ||||||||||||||||||||||
const transformArrCache: string[] = [] | ||||||||||||||||||||||
const transformArrCache: CSSProperties[] = [] | ||||||||||||||||||||||
Object.keys(numberItems).forEach((key: any) => { | ||||||||||||||||||||||
const elem = numberItems[Number(key)] as HTMLElement | ||||||||||||||||||||||
const idx = Number(numerArr[Number(key)]) | ||||||||||||||||||||||
if (elem) { | ||||||||||||||||||||||
const idx = Number(numberArr[Number(key)]) | ||||||||||||||||||||||
const enabled = | ||||||||||||||||||||||
elem && typeof idx === 'number' && !Number.isNaN(idx) | ||||||||||||||||||||||
if (enabled) { | ||||||||||||||||||||||
// 计算规则:父元素和实际列表高度的百分比,分割成20等份 | ||||||||||||||||||||||
const transform = | ||||||||||||||||||||||
idx || idx === 0 | ||||||||||||||||||||||
? `translate(0, -${(idx === 0 ? 10 : idx) * 5}%)` | ||||||||||||||||||||||
: '' | ||||||||||||||||||||||
transformArrCache.push(transform) | ||||||||||||||||||||||
transformArrCache.push({ | ||||||||||||||||||||||
transitionDuration: `${duration}s`, | ||||||||||||||||||||||
transform, | ||||||||||||||||||||||
} as CSSProperties) | ||||||||||||||||||||||
Comment on lines
+78
to
+81
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. 🛠️ Refactor suggestion 优化了动画过渡效果的实现 使用对象形式管理样式属性是个很好的改进,但建议考虑性能优化: -transformArrCache.push({
- transitionDuration: `${duration}s`,
- transform,
-} as CSSProperties)
+const style: CSSProperties = {
+ transitionDuration: `${duration}s`,
+ transform,
+ willChange: 'transform'
+}
+transformArrCache.push(style) 添加 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||
} | ||||||||||||||||||||||
}) | ||||||||||||||||||||||
setTransformArr([...transformArrCache]) | ||||||||||||||||||||||
}) | ||||||||||||||||||||||
.exec() | ||||||||||||||||||||||
} | ||||||||||||||||||||||
}, [numerArr]) | ||||||||||||||||||||||
|
||||||||||||||||||||||
const numberEaseStyle = (idx: number) => { | ||||||||||||||||||||||
return { | ||||||||||||||||||||||
transition: `transform ${duration}s ease-in-out`, | ||||||||||||||||||||||
transform: transformArr[idx] ? transformArr[idx] : null, | ||||||||||||||||||||||
} as CSSProperties | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||
setNumberTransform() | ||||||||||||||||||||||
}, [numerArr, setNumberTransform]) | ||||||||||||||||||||||
}, [numberArr]) | ||||||||||||||||||||||
|
||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||
if (!isLoaded.current) { | ||||||||||||||||||||||
isLoaded.current = true | ||||||||||||||||||||||
timerRef.current = window.setTimeout(() => { | ||||||||||||||||||||||
setNumerArr(getShowNumber()) | ||||||||||||||||||||||
}, delay) | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
setNumerArr(getShowNumber()) | ||||||||||||||||||||||
if (numberArr.length) { | ||||||||||||||||||||||
if (!isLoaded.current) { | ||||||||||||||||||||||
isLoaded.current = true | ||||||||||||||||||||||
timerRef.current = setTimeout(() => { | ||||||||||||||||||||||
setNumberTransform() | ||||||||||||||||||||||
}, delay) | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
setNumberTransform() | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
return () => { | ||||||||||||||||||||||
window.clearTimeout(timerRef.current) | ||||||||||||||||||||||
clearTimeout(timerRef.current) | ||||||||||||||||||||||
isLoaded.current = false | ||||||||||||||||||||||
} | ||||||||||||||||||||||
}, [value, delay, getShowNumber]) | ||||||||||||||||||||||
}, [numberArr, delay, setNumberTransform]) | ||||||||||||||||||||||
|
||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||
setNumberArr(getShowNumber()) | ||||||||||||||||||||||
}, [value, getShowNumber]) | ||||||||||||||||||||||
|
||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<View className={`${classPrefix} ${className}`} ref={countupRef}> | ||||||||||||||||||||||
<ul className={`${classPrefix}-list`}> | ||||||||||||||||||||||
{numerArr.map((item: string, idx: number) => { | ||||||||||||||||||||||
<View className={`${classPrefix} ${className}`} ref={countupRef} {...rest}> | ||||||||||||||||||||||
<View className={`${classPrefix}-list`}> | ||||||||||||||||||||||
{numberArr.map((item: string, idx: number) => { | ||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<li | ||||||||||||||||||||||
<View | ||||||||||||||||||||||
className={`${classPrefix}-listitem ${ | ||||||||||||||||||||||
!Number.isNaN(Number(item)) | ||||||||||||||||||||||
? `${classPrefix}-listitem-number` | ||||||||||||||||||||||
|
@@ -121,21 +122,28 @@ export const CountUp: FunctionComponent<Partial<CountUpProps>> = (props) => { | |||||||||||||||||||||
key={idx} | ||||||||||||||||||||||
> | ||||||||||||||||||||||
{!Number.isNaN(Number(item)) ? ( | ||||||||||||||||||||||
<span | ||||||||||||||||||||||
<View | ||||||||||||||||||||||
className={`${classPrefix}-number`} | ||||||||||||||||||||||
style={numberEaseStyle(idx)} | ||||||||||||||||||||||
style={transformArr?.[idx]} | ||||||||||||||||||||||
> | ||||||||||||||||||||||
{[...numbers, ...numbers].map((number, subidx) => { | ||||||||||||||||||||||
return <span key={subidx}>{number}</span> | ||||||||||||||||||||||
return ( | ||||||||||||||||||||||
<Text | ||||||||||||||||||||||
className={`${classPrefix}-number-text`} | ||||||||||||||||||||||
key={subidx} | ||||||||||||||||||||||
> | ||||||||||||||||||||||
{number} | ||||||||||||||||||||||
</Text> | ||||||||||||||||||||||
) | ||||||||||||||||||||||
})} | ||||||||||||||||||||||
</span> | ||||||||||||||||||||||
</View> | ||||||||||||||||||||||
Comment on lines
+125
to
+139
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. 🛠️ Refactor suggestion 渲染逻辑可以进行性能优化 当前实现在渲染数字时可能会导致不必要的重渲染。建议以下优化:
+const NumberItem = memo(({ number }: { number: number }) => (
+ <Text className="nut-countup-number-text">
+ {number}
+ </Text>
+))
+
+NumberItem.displayName = 'NumberItem'
// 在原渲染逻辑中使用
-{[...numbers, ...numbers].map((number, subidx) => (
- <Text className={`${classPrefix}-number-text`} key={subidx}>
- {number}
- </Text>
-))}
+{[...numbers, ...numbers].map((number, subidx) => (
+ <NumberItem key={subidx} number={number} />
+))}
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. 可以尝试 |
||||||||||||||||||||||
) : ( | ||||||||||||||||||||||
<span className={`${classPrefix}-separator`}>{item}</span> | ||||||||||||||||||||||
<View className={`${classPrefix}-separator`}>{item}</View> | ||||||||||||||||||||||
)} | ||||||||||||||||||||||
</li> | ||||||||||||||||||||||
</View> | ||||||||||||||||||||||
) | ||||||||||||||||||||||
})} | ||||||||||||||||||||||
</ul> | ||||||||||||||||||||||
</View> | ||||||||||||||||||||||
</View> | ||||||||||||||||||||||
) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
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.
3.0 标识涵盖鸿蒙适配,这种单独的 v14 适配,和 3.0 标识冲突。需要大家进行方案确认。
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.
已确认