uni-app 动画效果

章节介绍

在移动应用开发中,流畅的动画效果是提升用户体验的重要因素。uni-app 提供了丰富的动画 API 和实现方式,使开发者能够轻松创建各种动画效果。本章节将详细介绍 uni-app 中的动画实现方法,包括基础动画 API、过渡效果以及复杂的动画序列,帮助你掌握如何为应用添加生动流畅的动画效果。

核心知识点讲解

1. 动画 API 概述

uni-app 提供了两种主要的动画实现方式:

  1. CSS 动画:使用 CSS3 的 animationtransition 属性
  2. JS 动画 API:使用 uni-app 封装的 uni.createAnimation 方法

CSS 动画

CSS 动画适用于简单的、预定义的动画效果,如元素的淡入淡出、平移、旋转等。

/* 定义动画 */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* 使用动画 */
.animated-element {
  animation: fadeIn 0.5s ease-in-out;
}

JS 动画 API

JS 动画 API 提供了更灵活的动画控制能力,适用于复杂的、需要动态控制的动画效果。

// 创建动画实例
const animation = uni.createAnimation({
  duration: 500,  // 动画持续时间
  timingFunction: 'ease',  // 动画曲线
  delay: 0,  // 动画延迟时间
  transformOrigin: '50% 50% 0'  // 动画原点
});

// 定义动画步骤
animation.translateX(100).rotate(180).step();

// 导出动画数据
this.animationData = animation.export();

// 在模板中使用
// <view animation="{{animationData}}"></view>

2. 过渡效果

过渡效果是指元素在状态变化时的平滑过渡,如元素的显示/隐藏、位置变化等。

基本过渡效果

/* 基本过渡效果 */
.transition-element {
  transition: all 0.3s ease;
}

.transition-element:hover {
  transform: scale(1.1);
  color: #ff4d4f;
}

条件渲染中的过渡

在使用 v-ifv-show 等指令进行条件渲染时,可以结合过渡类实现平滑的过渡效果。

<template>
  <view>
    <button @click="show = !show">切换显示</button>
    <view class="transition-box" v-show="show"></view>
  </view>
</template>

<style>
.transition-box {
  width: 200rpx;
  height: 200rpx;
  background-color: #409eff;
  transition: all 0.3s ease;
}

.transition-box[v-show="false"] {
  opacity: 0;
  transform: scale(0.8);
}
</style>

<script>
export default {
  data() {
    return {
      show: true
    };
  }
};
</script>

3. 动画序列

动画序列是指多个动画按照一定的顺序执行,形成连贯的动画效果。

链式动画

使用 JS 动画 API 可以创建链式动画,通过多次调用 step() 方法实现。

// 创建动画实例
const animation = uni.createAnimation({
  duration: 500,
  timingFunction: 'ease'
});

// 第一个动画:平移
animation.translateX(100).step();

// 第二个动画:旋转
animation.rotate(180).step();

// 第三个动画:缩放
animation.scale(0.8).step();

// 导出动画数据
this.animationData = animation.export();

延迟动画

通过设置不同的 delay 参数,可以实现动画的延迟执行。

// 创建动画实例
const animation1 = uni.createAnimation({
  duration: 500,
  timingFunction: 'ease',
  delay: 0
});

const animation2 = uni.createAnimation({
  duration: 500,
  timingFunction: 'ease',
  delay: 200
});

// 执行第一个动画
animation1.translateX(100).step();
this.animationData1 = animation1.export();

// 执行第二个动画
animation2.translateX(100).step();
this.animationData2 = animation2.export();

实用案例分析

案例:实现页面切换动画

在 uni-app 中,可以通过配置 pages.json 文件实现页面切换动画,也可以通过自定义动画实现更灵活的页面转场效果。

1. 配置页面切换动画

pages.json 文件中,可以为全局或单个页面配置转场动画:

{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页",
        "app-plus": {
          "animationType": "slide-in-right",
          "animationDuration": 300
        }
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "uni-app",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8",
    "app-plus": {
      "animationType": "fade-in",
      "animationDuration": 300
    }
  }
}

2. 自定义页面切换动画

对于更复杂的页面切换动画,可以使用自定义组件和动画 API 实现:

<!-- 页面切换动画组件 -->
<template>
  <view class="page-transition" :class="{ 'enter': enter, 'leave': leave }">
    <slot></slot>
  </view>
</template>

<style scoped>
.page-transition {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transition: all 0.3s ease;
}

.page-transition.enter {
  transform: translateX(100%);
  opacity: 0;
}

.page-transition.enter-active {
  transform: translateX(0);
  opacity: 1;
}

.page-transition.leave {
  transform: translateX(0);
  opacity: 1;
}

.page-transition.leave-active {
  transform: translateX(-100%);
  opacity: 0;
}
</style>

<script>
export default {
  data() {
    return {
      enter: true,
      leave: false
    };
  },
  mounted() {
    // 触发进入动画
    this.$nextTick(() => {
      this.enter = true;
    });
  },
  methods: {
    // 触发离开动画
    leave() {
      this.leave = true;
      setTimeout(() => {
        this.$emit('leave-done');
      }, 300);
    }
  }
};
</script>

3. 页面切换动画使用示例

<!-- 页面 A -->
<template>
  <view class="container">
    <text>页面 A</text>
    <button @click="navigateToPageB">跳转到页面 B</button>
  </view>
</template>

<script>
export default {
  methods: {
    navigateToPageB() {
      uni.navigateTo({
        url: '/pages/pageB/pageB'
      });
    }
  }
};
</script>

<!-- 页面 B -->
<template>
  <page-transition ref="transition">
    <view class="container">
      <text>页面 B</text>
      <button @click="navigateBack">返回页面 A</button>
    </view>
  </page-transition>
</template>

<script>
import PageTransition from '@/components/page-transition.vue';

export default {
  components: {
    PageTransition
  },
  methods: {
    navigateBack() {
      this.$refs.transition.leave();
      setTimeout(() => {
        uni.navigateBack();
      }, 100);
    }
  }
};
</script>

常见问题与解决方案

1. 动画不流畅

问题:动画执行时出现卡顿或不流畅的情况。

解决方案

  • 优先使用 CSS 动画,因为 CSS 动画由 GPU 加速
  • 避免在动画过程中修改布局属性(如 width、height、top、left 等)
  • 使用 transformopacity 属性进行动画,这些属性不会触发重排
  • 对于复杂动画,考虑使用 requestAnimationFrame 优化

2. 动画在不同平台表现不一致

问题:同一动画在不同平台(如 iOS 和 Android)表现不一致。

解决方案

  • 测试不同平台的动画效果,针对差异进行适配
  • 使用条件编译为不同平台提供不同的动画实现
  • 优先使用 uni-app 官方推荐的动画 API 和实现方式
  • 对于复杂动画,考虑使用第三方动画库如 lottie-web

3. 动画结束后元素位置重置

问题:使用 uni.createAnimation 创建的动画结束后,元素位置会重置到初始状态。

解决方案

  • 动画结束后,手动更新元素的样式属性
  • 使用 uni.createAnimationfillMode 参数(仅支持部分平台)
  • 对于需要持久化的动画效果,考虑使用 CSS 类切换而不是 JS 动画

代码优化建议

1. 动画性能优化

// 优化前:直接修改样式属性
this.style.top = '100px';
this.style.left = '100px';

// 优化后:使用 transform 属性
this.style.transform = 'translate(100px, 100px)';

2. 动画代码复用

// 优化前:重复创建动画实例
const animation1 = uni.createAnimation({ duration: 300 });
animation1.translateX(100).step();
this.animationData1 = animation1.export();

const animation2 = uni.createAnimation({ duration: 300 });
animation2.translateY(100).step();
this.animationData2 = animation2.export();

// 优化后:封装动画工具函数
methods: {
  createAnimation(styles, duration = 300) {
    const animation = uni.createAnimation({ duration });
    Object.keys(styles).forEach(key => {
      animation[key](styles[key]);
    });
    animation.step();
    return animation.export();
  }
}

// 使用
this.animationData1 = this.createAnimation({ translateX: 100 });
this.animationData2 = this.createAnimation({ translateY: 100 });

3. 动画序列管理

// 优化前:嵌套 setTimeout
setTimeout(() => {
  // 第一个动画
  this.animate1 = true;
  
  setTimeout(() => {
    // 第二个动画
    this.animate2 = true;
    
    setTimeout(() => {
      // 第三个动画
      this.animate3 = true;
    }, 300);
  }, 300);
}, 300);

// 优化后:使用 Promise 链
methods: {
  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  },
  
  async runAnimationSequence() {
    // 第一个动画
    this.animate1 = true;
    await this.delay(300);
    
    // 第二个动画
    this.animate2 = true;
    await this.delay(300);
    
    // 第三个动画
    this.animate3 = true;
  }
}

章节总结

本章节详细介绍了 uni-app 中的动画效果实现方法,包括:

  1. 动画 API 概述:介绍了 CSS 动画和 JS 动画 API 的使用方法
  2. 过渡效果:讲解了如何实现元素状态变化时的平滑过渡
  3. 动画序列:介绍了如何创建链式动画和延迟动画
  4. 实用案例:通过页面切换动画的实现,展示了动画效果在实际应用中的使用
  5. 常见问题与解决方案:针对动画实现中常见的问题提供了解决方案
  6. 代码优化建议:提供了动画性能优化、代码复用和动画序列管理的优化建议

通过本章节的学习,你应该能够掌握 uni-app 中各种动画效果的实现方法,为你的应用添加流畅、生动的动画效果,提升用户体验。在实际开发中,应根据具体场景选择合适的动画实现方式,并注意优化动画性能,确保动画效果流畅自然。

« 上一篇 uni-app 列表开发 下一篇 » uni-app 状态管理