Skip to content

Commit df5fd80

Browse files
authored
Merge pull request #2364 from didi/feat-transion-25.05.10
transition动画
2 parents 759dbda + 7de870e commit df5fd80

File tree

10 files changed

+885
-327
lines changed

10 files changed

+885
-327
lines changed

docs-vitepress/guide/rn/style.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,3 +1429,110 @@ object-fit: contain; /* 完整显示,保持比例 */
14291429
object-fit: cover; /* 覆盖填充,保持比例,可能裁剪 */
14301430
object-fit: scale-down; /* 缩小显示 */
14311431
```
1432+
1433+
1434+
## 跨端动画
1435+
基础组件 view 支持两种动画形式 createAnimation API 和 transition,
1436+
可以通过设置 animation 属于来使用 createAnimation API 动画,通过 class 或者 style 设置 css transition 来使用 transition 动画,
1437+
可以用过 prop enableAnimation = api/transition 来指定使用 createAnimation API/transition 的动画形式,,enableAnimation 设置 true 默认为 createAnimation API 形式,需要注意的是指定动画类型后,对应的动画参数也需要匹配设置,详细使用文档如下:
1438+
1439+
### createAnimation 动画API
1440+
创建一个动画实例 animation,调用实例的方法来描述动画,最后通过动画实例的 export 方法导出动画数据传递给组件的 animation 属性。
1441+
详情参考以下动画部分微信小程序文档,以下仅描述支持能力有差异部分:
1442+
#### [wx.createAnimation](https://developers.weixin.qq.com/miniprogram/dev/api/ui/animation/wx.createAnimation.html)
1443+
- 参数 timingFunction 不支持 step-start 和 step-end
1444+
#### [动画实例 animation](https://developers.weixin.qq.com/miniprogram/dev/api/ui/animation/Animation.html)
1445+
- translateZ() 不支持
1446+
- translate3d() 不支持
1447+
- rotate3d() 不支持
1448+
- rotateZ() 不支持
1449+
- scaleZ() 不支持
1450+
- scale3d() 不支持
1451+
- animation.matrix() 不支持
1452+
- animation.matrix3d() 不支持
1453+
1454+
### CSS transition
1455+
CSS transition 动画至少需要设置动画时长和动画属性,可通过单独属性 transition-property 和 transition-property 设置,也可以通过 transition 缩写设置
1456+
>重要提示:transition 支持设置百分比,如 ```marginTop: 1%;marginTop: 100%;```;要注意的是起始值和结束值需设置为同一类型,同为px或者同为百分比, 支持 ```marginTop: 10px;marginTop: 100px; ```**不支持 ```marginTop: 10px; marginTop: 100%;```**
1457+
1458+
#### [transition](https://developer.mozilla.org/en-US/docs/Web/CSS/transition)
1459+
```css
1460+
/**** 支持 */
1461+
/* property name | duration */
1462+
transition: margin-right 4s;
1463+
/* property name | duration | delay */
1464+
transition: margin-right 4s 1s;
1465+
/* property name | duration | easing function */
1466+
transition: margin-right 4s ease-in-out;
1467+
/* property name | duration | easing function | delay */
1468+
transition: margin-right 4s ease-in-out 1s;
1469+
1470+
/* Apply to 2 properties */
1471+
transition: margin-right 4s, color 1s;
1472+
```
1473+
```css
1474+
/**** 需配合 transition-property 使用*/
1475+
/* transition 未定义 property 时需配合 transition-property 使用,否则仅设置duration、timingFunciton等参数实际动画不生效 */
1476+
transition: 200ms linear 50ms;
1477+
transition: 2s, 1s;
1478+
```
1479+
```css
1480+
/**** 不支持:property 不支持设置为 all */
1481+
transition: all 0.5s ease-out
1482+
```
1483+
#### [transition-property](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-property)
1484+
不支持设置为 all,不支持自定义
1485+
> 支持的 property 合集有:
1486+
> rotateX rotateY rotateZ scaleX scaleY skewX skewY translateX translateY opacity backgroundColor width height top right bottom left color borderColor borderBottomColor borderLeftColor borderRightColor borderTopColor borderTopLeftRadius borderTopRightRadius borderBottomLeftRadius borderBottomRightRadius borderRadius borderBottomWidth borderLeftWidth borderRightWidth borderTopWidth borderWidth margin marginBottom marginLeft marginRight marginTop maxHeight maxWidth minHeight minWidth padding paddingBottom paddingLeft paddingRight paddingTop
1487+
```css
1488+
/**** 支持 */
1489+
transition-property: height;
1490+
transition-property: height, color;
1491+
```
1492+
```css
1493+
/**** 不支持 */
1494+
transition-property: all;
1495+
/* <custom-ident> values */
1496+
transition-property: test_05;
1497+
transition-property: -specific;
1498+
transition-property: sliding-vertically;
1499+
transition-property: test1, animation4;
1500+
transition-property: all, -moz-specific, sliding;
1501+
transition-property: inherit;
1502+
transition-property: initial;
1503+
transition-property: revert;
1504+
transition-property: revert-layer;
1505+
transition-property: unset;
1506+
```
1507+
#### [transition-duration](https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-duration)
1508+
```css
1509+
/**** 支持 */
1510+
transition-duration: 6s;
1511+
transition-duration: 120ms;
1512+
transition-duration: 1s, 15s;
1513+
transition-duration: 10s, 30s, 230ms;
1514+
```
1515+
#### [transition-delay](https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-delay)
1516+
```css
1517+
/**** 支持 */
1518+
transition-delay: 3s;
1519+
transition-delay: 2s, 4ms;
1520+
```
1521+
#### [transition-behavior](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior)
1522+
不支持
1523+
#### [transition-timing-function](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function)
1524+
仅支持 ease、ease-inease-outease-in-out、linear、cubic-bezier(),不支持 step-startstep-end、steps()
1525+
1526+
### CSS animation
1527+
暂不支持
1528+
1529+
### 动画监听事件
1530+
#### transitionend
1531+
- CSS transition 结束或 wx.createAnimation 结束一个阶段时触发
1532+
- 不属于冒泡事件,需要绑定在真正发生了动画的节点上才会生效
1533+
#### animationstart
1534+
暂不支持
1535+
#### animationiteration
1536+
暂不支持
1537+
#### animationend
1538+
暂不支持

packages/webpack-plugin/lib/platform/style/wx/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const { parseValues } = require('../../../utils/string')
33

44
module.exports = function getSpec ({ warn, error }) {
55
// React Native 双端都不支持的 CSS property
6-
const unsupportedPropExp = /^(white-space|text-overflow|animation|transition|font-variant-caps|font-variant-numeric|font-variant-east-asian|font-variant-alternates|font-variant-ligatures|background-position|caret-color)$/
6+
const unsupportedPropExp = /^(white-space|text-overflow|animation|font-variant-caps|font-variant-numeric|font-variant-east-asian|font-variant-alternates|font-variant-ligatures|background-position|caret-color)$/
77
const unsupportedPropMode = {
88
// React Native ios 不支持的 CSS property
99
ios: /^(vertical-align)$/,
@@ -400,6 +400,8 @@ module.exports = function getSpec ({ warn, error }) {
400400
// css var & 数组直接返回
401401
if (Array.isArray(value) || cssVariableExp.test(value)) return { prop, value }
402402
const values = parseValues(value)
403+
// Todo transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
404+
values.sort()
403405
const transform = []
404406
values.forEach(item => {
405407
const match = item.match(/([/\w]+)\((.+)\)/)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { error, collectDataset, hasOwn } from '@mpxjs/utils'
2+
import { useRef } from 'react'
3+
import useAnimationAPIHooks from './useAnimationAPIHooks'
4+
import useTransitionHooks from './useTransitionHooks'
5+
import type { AnimatableValue } from 'react-native-reanimated'
6+
import type { MutableRefObject } from 'react'
7+
import type { NativeSyntheticEvent } from 'react-native'
8+
import type { _ViewProps } from '../mpx-view'
9+
10+
// 动画类型
11+
export type AnimationType = 'api'|'animation'|'transition'|'none'
12+
13+
export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAnimation?: boolean | AnimationType, layoutRef: MutableRefObject<any>, transitionend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void }) {
14+
const { style: originalStyle = {}, enableAnimation, animation, transitionend, layoutRef } = props
15+
// 记录动画类型
16+
let animationType = ''
17+
if (hasOwn(originalStyle, 'animation') || (hasOwn(originalStyle, 'animationName') && hasOwn(originalStyle, 'animationDuration'))) {
18+
// css animation 只做检测提示
19+
animationType = 'animation'
20+
}
21+
if (!!animation || enableAnimation === true) {
22+
animationType = 'api'
23+
}
24+
// 优先级 css transition > API
25+
if (hasOwn(originalStyle, 'transition') || (hasOwn(originalStyle, 'transitionProperty') && hasOwn(originalStyle, 'transitionDuration'))) {
26+
animationType = 'transition'
27+
}
28+
// 优先以 enableAnimation 定义类型为准
29+
if (enableAnimation === 'api' || enableAnimation === 'transition' || enableAnimation === 'animation') {
30+
animationType = enableAnimation
31+
}
32+
const animationTypeRef = useRef(animationType)
33+
if (animationType! && animationTypeRef.current !== animationType) {
34+
// 允许 API、CssTransition 到 none,不允许 API、CssTransition 互切,不允许 none 到 API、CssTransition
35+
error('[Mpx runtime error]: The animation type should be stable in the component lifecycle, or you can set animation type with [enable-animation].')
36+
}
37+
if (animationType === 'animation') {
38+
// 暂不支持 CssAnimation 提示
39+
error('[Mpx runtime error]: CSS animation is not supported yet')
40+
return { enableStyleAnimation: false }
41+
}
42+
if (!animationTypeRef.current) return { enableStyleAnimation: false }
43+
44+
const hooksProps = { style: originalStyle }
45+
if (transitionend && typeof transitionend === 'function') {
46+
function withTimingCallback (finished?: boolean, current?: AnimatableValue, duration?: number) {
47+
const target = {
48+
id: animation?.id || -1,
49+
dataset: collectDataset(props),
50+
offsetLeft: layoutRef?.current?.offsetLeft || 0,
51+
offsetTop: layoutRef?.current?.offsetTop || 0
52+
}
53+
transitionend!({
54+
type: 'transitionend',
55+
// elapsedTime 对齐wx 单位s
56+
detail: { elapsedTime: duration ? duration / 1000 : 0, finished, current },
57+
target,
58+
currentTarget: target,
59+
timeStamp: Date.now()
60+
})
61+
}
62+
Object.assign(hooksProps, { transitionend: withTimingCallback })
63+
}
64+
if (animationTypeRef.current === 'api') {
65+
Object.assign(hooksProps, { animation })
66+
}
67+
return {
68+
enableStyleAnimation: !!animationTypeRef.current,
69+
animationStyle: animationTypeRef.current === 'api'
70+
// eslint-disable-next-line react-hooks/rules-of-hooks
71+
? useAnimationAPIHooks(hooksProps)
72+
// eslint-disable-next-line react-hooks/rules-of-hooks
73+
: useTransitionHooks(hooksProps)
74+
}
75+
}

0 commit comments

Comments
 (0)