perf(NumberRoll): 优化数字滚动动画性能和渲染效果
- 使用更平滑的缓动函数 easeOutQuart 替代 easeOutCubic - 减少不必要的值更新,只在变化明显时更新 - 添加硬件加速优化(translateZ(0)) - 移除CSS transition,完全由JS控制动画 - 添加文本渲染优化属性
Showing
1 changed file
with
32 additions
and
9 deletions
| ... | @@ -8,7 +8,10 @@ | ... | @@ -8,7 +8,10 @@ |
| 8 | <view class="digit-wrapper"> | 8 | <view class="digit-wrapper"> |
| 9 | <view | 9 | <view |
| 10 | class="digit-column" | 10 | class="digit-column" |
| 11 | - :style="{ transform: `translateY(-${digit.currentValue * 10}%)` }" | 11 | + :style="{ |
| 12 | + transform: `translateY(-${digit.currentValue * 10}%) translateZ(0)`, | ||
| 13 | + willChange: isAnimating ? 'transform' : 'auto' | ||
| 14 | + }" | ||
| 12 | > | 15 | > |
| 13 | <view | 16 | <view |
| 14 | v-for="num in 10" | 17 | v-for="num in 10" |
| ... | @@ -115,12 +118,17 @@ const animateDigit = (digit, index) => { | ... | @@ -115,12 +118,17 @@ const animateDigit = (digit, index) => { |
| 115 | const elapsed = currentTime - startTime | 118 | const elapsed = currentTime - startTime |
| 116 | const progress = Math.min(elapsed / props.duration, 1) | 119 | const progress = Math.min(elapsed / props.duration, 1) |
| 117 | 120 | ||
| 118 | - // 使用缓动函数 | 121 | + // 使用更平滑的缓动函数 |
| 119 | - const easeProgress = easeOutCubic(progress) | 122 | + const easeProgress = easeOutQuart(progress) |
| 120 | 123 | ||
| 121 | - // 计算当前值 | 124 | + // 计算当前值,使用更精确的计算 |
| 122 | const currentValue = startValue + (endValue - startValue) * easeProgress | 125 | const currentValue = startValue + (endValue - startValue) * easeProgress |
| 123 | - digit.currentValue = currentValue | 126 | + |
| 127 | + // 减少不必要的更新,只在值有明显变化时更新 | ||
| 128 | + const roundedValue = Math.round(currentValue * 100) / 100 | ||
| 129 | + if (Math.abs(digit.currentValue - roundedValue) > 0.01) { | ||
| 130 | + digit.currentValue = roundedValue | ||
| 131 | + } | ||
| 124 | 132 | ||
| 125 | if (progress < 1) { | 133 | if (progress < 1) { |
| 126 | digit.animationId = requestAnimationFrame(animate) | 134 | digit.animationId = requestAnimationFrame(animate) |
| ... | @@ -133,9 +141,9 @@ const animateDigit = (digit, index) => { | ... | @@ -133,9 +141,9 @@ const animateDigit = (digit, index) => { |
| 133 | digit.animationId = requestAnimationFrame(animate) | 141 | digit.animationId = requestAnimationFrame(animate) |
| 134 | } | 142 | } |
| 135 | 143 | ||
| 136 | -// 缓动函数 | 144 | +// 更平滑的缓动函数 |
| 137 | -const easeOutCubic = (t) => { | 145 | +const easeOutQuart = (t) => { |
| 138 | - return 1 - Math.pow(1 - t, 3) | 146 | + return 1 - Math.pow(1 - t, 4) |
| 139 | } | 147 | } |
| 140 | 148 | ||
| 141 | // 检查动画是否完成 | 149 | // 检查动画是否完成 |
| ... | @@ -239,6 +247,10 @@ defineExpose({ | ... | @@ -239,6 +247,10 @@ defineExpose({ |
| 239 | background: rgba(255, 255, 255, 0.1); | 247 | background: rgba(255, 255, 255, 0.1); |
| 240 | border-radius: 8rpx; | 248 | border-radius: 8rpx; |
| 241 | border: 1rpx solid rgba(255, 255, 255, 0.2); | 249 | border: 1rpx solid rgba(255, 255, 255, 0.2); |
| 250 | + // 启用硬件加速 | ||
| 251 | + transform: translateZ(0); | ||
| 252 | + backface-visibility: hidden; | ||
| 253 | + perspective: 1000px; | ||
| 242 | } | 254 | } |
| 243 | 255 | ||
| 244 | .digit-wrapper { | 256 | .digit-wrapper { |
| ... | @@ -246,6 +258,8 @@ defineExpose({ | ... | @@ -246,6 +258,8 @@ defineExpose({ |
| 246 | width: 100%; | 258 | width: 100%; |
| 247 | height: 100%; | 259 | height: 100%; |
| 248 | overflow: hidden; | 260 | overflow: hidden; |
| 261 | + // 启用硬件加速 | ||
| 262 | + transform: translateZ(0); | ||
| 249 | } | 263 | } |
| 250 | 264 | ||
| 251 | .digit-column { | 265 | .digit-column { |
| ... | @@ -253,7 +267,11 @@ defineExpose({ | ... | @@ -253,7 +267,11 @@ defineExpose({ |
| 253 | top: 0; | 267 | top: 0; |
| 254 | left: 0; | 268 | left: 0; |
| 255 | width: 100%; | 269 | width: 100%; |
| 256 | - transition: transform 0.1s ease-out; | 270 | + // 移除CSS transition,完全由JS控制动画 |
| 271 | + // transition: transform 0.1s ease-out; | ||
| 272 | + // 启用硬件加速和优化 | ||
| 273 | + transform-style: preserve-3d; | ||
| 274 | + backface-visibility: hidden; | ||
| 257 | } | 275 | } |
| 258 | 276 | ||
| 259 | .digit-item { | 277 | .digit-item { |
| ... | @@ -266,5 +284,10 @@ defineExpose({ | ... | @@ -266,5 +284,10 @@ defineExpose({ |
| 266 | font-weight: bold; | 284 | font-weight: bold; |
| 267 | color: #fff; | 285 | color: #fff; |
| 268 | font-family: 'Courier New', monospace; | 286 | font-family: 'Courier New', monospace; |
| 287 | + // 文本渲染优化 | ||
| 288 | + text-rendering: optimizeSpeed; | ||
| 289 | + -webkit-font-smoothing: antialiased; | ||
| 290 | + // 启用硬件加速 | ||
| 291 | + transform: translateZ(0); | ||
| 269 | } | 292 | } |
| 270 | </style> | 293 | </style> | ... | ... |
-
Please register or login to post a comment