Mpx 动画

前言

对于 Mpx 的动画方案,要实现多端兼容的目的(微信小程序、Android、iOS...)

  1. 最初方案:条件编译 ------ 在 Mpx 代码中嵌 RN 代码,借助 RN 动画库写一套动画,然后 CSS 写一套以适配多端

  2. 现在方案:Mpx 动画 API (即微信小程序动画API)

在 Mpx 中嵌RN动画

  1. 如果你的组件是 setup 语法,那不建议用这种写法,这种实现方式的前提是选项式写法。
  2. 引入 REACTHOOKSEXEC ,它允许我们在 mpx 嵌套 RN

组件使用的值需要通过 REACTHOOKSEXEC方法的返回值的方式进行声明。

(1) 导入必要的组件和函数

js 复制代码
import Animated, { useSharedValue, withTiming, useAnimatedStyle } from 'react-native-reanimated';

(2) 定义共享值

使用 useSharedValue 创建一个可以驱动动画的共享值。你可以把它想象成一个 React 状态,它会自动在应用的 JavaScript 端 和 原生端 之间保持同步(因此得名)。

js 复制代码
const translateX = useSharedValue(0); // 初始值为 0

(3) 定义动画样式

使用 useAnimatedStyle 将共享值应用到组件的样式上。通过 useAnimatedStyle,你可以将 SharedValue 的值映射到样式属性。

js 复制代码
const transformStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
}));

(4) 触发动画

通过修改共享值来触发动画。可以使用 withSpring、withTiming 等用于创建平滑过渡动画的函数。

js 复制代码
const onClick = () => {
  translateX.value = withTiming(2100); // 向右移动 200 个单位
};

完整代码:

js 复制代码
<template>
  <button bindtap="onClick">开始</button>
  <AnimatedView style="{{transformStyle}}">
    <view class="item" />
  </AnimatedView>
</template>

<script lang="ts">
import { createComponent, REACTHOOKSEXEC } from '@mpxjs/core'
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withTiming
} from 'react-native-reanimated'

createComponent({
  properties: {},
  components: {
    AnimatedView: Animated.View
  },
  [REACTHOOKSEXEC](props: any) {
    const translateValue = useSharedValue(0)
    const transformStyle = useAnimatedStyle(() => ({
      transform: [{ translateX: translateValue.value }]
    }))
    const onClick = () => {
      translateValue.value = withTiming(200)
    }
    return {
      transformStyle,
      onClick
    }
  }
})
</script>

Mpx 动画API

1. mpx.createAnimation

创建一个动画实例 animation,调用实例的方法来描述动画。最后通过动画实例的 export 方法导出动画数据传递给组件的 animation 属性。

属性 类型 默认值 必填 说明
duration number 400 动画持续时间,单位 ms
timingFunction string 'linear' 动画的效果
delay number 0 动画延迟时间,单位 ms
transformOrigin string '50% 50% 0' 动画执行时变换的原点

timingFunction 可配置的值

合法值 说明 备注
'linear' 动画从头到尾的速度是相同的
'ease' 动画以低速开始,然后加快,在结束前变慢
'ease-in' 动画以低速开始
'ease-in-out' 动画以低速开始和结束
'ease-out' 动画以低速结束
'step-start' 动画第一帧就跳至结束状态直到结束 RN不支持
'step-end' 动画一直保持开始状态,最后一帧跳到结束状态 RN不支持
js 复制代码
<template>
  <view class="container">
    <view animation="{{animationData}}" />
  </view>
</template>

<script setup>
  import mpx, { ref } from '@mpxjs/core'
  const animation = mpx.createAnimation({
    duration: 1000,
    timingFunction: 'ease',
    delay: 0,
    transformOrigin: '50% 50% 0'
  })
  const animationData = ref({})

  defineExpose({
    animationData
  })
</script>

2. Animation.step(Object object)

表示一组动画完成。可以在一组动画中调用任意多个动画方法,一组动画中的所有动画会同时开始,一组动画完成后才会进行下一组动画。

  • 用于表示一个动画步骤的结束
  • 每次调用 step() 都会生成一个新的动画关键帧
  • 可以设置动画的持续时间、延迟、时间函数、原点参数,与 wx.createAnimation 参数一致
  • 必须在调用 export() 之前调用

3. Animation.export()

导出动画队列。export 方法每次调用后会清掉之前的动画操作。

  • 用于导出当前动画的配置数据
  • 返回一个包含动画信息的对象
  • 这个对象可以直接绑定到模板的 animation 属性
  • 必须在调用 step() 之后调用

导出的数据通过数据绑定更新视图

🙋‍♀️🌰:

js 复制代码
<template>
  <view class="container">
    <button class="btn" bindtap="animateX">animateX</button>
    <view class="item" animation="{{animationData}}" />
  </view>
</template>

<script setup>
  import mpx, { ref } from '@mpxjs/core'
  const animation = mpx.createAnimation({
    duration: 1000,
    timingFunction: 'ease'
  })
  const animationData = ref({})

  const animateX = () => {
    animationData.value = animation.translateX(100).step().export() // 水平移动 100px
  }

  defineExpose({
    animationData,
    animateX,
  })
</script>

这样就能实现一个简单的水平动画

4. 变换方法

方法 介绍 备注
translate, translateX, translateY, translateZ, translate3d 用于设置平移变换 RN 目前不支持 translateZ 和 translate3d
matrix , matrix3d 用于设置矩阵变换 RN 目前不支持
rotate, rotateX, rotateY, rotateZ, rotate3d 用于设置旋转变换
scale, scaleX, scaleY, scaleZ, scale3d 用于设置缩放变换 RN 目前不支持 scaleZ 和 scale3d
skew, skewX, skewY 用于设置倾斜变换 Android skewX 变换偏差

5. 样式属性

这些方法用于设置动画的样式属性。

  • opacity
  • backgroundColor
  • width
  • height
  • top
  • right
  • bottom
  • left

基本使用步骤

1. 定义动画

  • 使用 mpx.createAnimation 初始化动画实例。
  • 设置动画的变换和样式属性。
  • 使用 step 方法定义关键帧,并为每个关键帧设置持续时间、延迟、时间函数等。
js 复制代码
const animation = mpx.createAnimation({
  duration: 1000,
  timingFunction: 'ease',
  delay: 0,
  transformOrigin: '50% 50% 0'
})

const animationData = ref({})

const handleClick = () => {
  animationData.value = animation.translateX(100).step().export() // 水平移动 100px
}

2. 导出动画数据

  • 使用 export 方法导出动画数据

3. 在模板中使用动画

js 复制代码
<view class="item" animation="{{animationData}}" />

4. 触发动画

  • 手动触发
    • 事件绑定
  • 自动触发
    • 生命周期
    • 回调

动画事件

使用 createAnimation 创建动画过程中,可以使用下述事件来监听动画事件。

但是目前 RN 支持该事件,在小程序中可以,如果只是在小程序中做一些回调可以使用。

事件名 含义 备注
transitionend wx.createAnimation 结束一个阶段 RN 不支持

还需要注意的是,这个事件不是冒泡事件,需要绑定在真正发生了动画的节点上才会生效。

js 复制代码
<view class="item" bindtransitionend="animationEnd" animation="{{animationData}}

进阶

mpx.createAnimation源码

RN 部分

源码创建了一个 Animated 类,定义和管理动画。声明哪些方法 RN 还未支持,提供了报错提示,通过 step 和 export 方法,生成动画数据并导出供其他组件使用

编译阶段,mpx 使用 useAnimationHooks() 这个钩子来将小程序语法转成 drn 语法,即 RN 动画库 react-native-reanimated 支持的语法。

主要阶段可以划分为:

  1. 当使用 mpx-view 标签时,钩子会检测入参是否含有 animation 这个属性,有则用 Animated.view 来代替 View 组件。
  2. 使用 useAnimationHooks 来将入参进行转义,最终适配 react-native-reanimated 语法

总结

  • mpx.createAnimation()基于小程序,通过转义也实现了 RN 的适配
  • 使用 mpx.createAnimation() 来实现动画,避免开发多套代码
  • 不足之处在于事件处理时并未做对应抹平

参考文档

相关推荐
FreeCultureBoy39 分钟前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom1 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom1 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom1 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom1 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom2 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试
LaoZhangAI3 小时前
2025最全GPT-4o图像生成API指南:官方接口配置+15个实用提示词【保姆级教程】
前端
ONE_Gua3 小时前
chromium魔改——CDP(Chrome DevTools Protocol)检测01
前端·后端·爬虫
LaoZhangAI3 小时前
2025最全Cherry Studio使用MCP指南:8种强大工具配置方法与实战案例
前端
咖啡教室3 小时前
前端开发日常工作每日记录笔记(2019至2024合集)
前端·javascript