Vue基础教程(138)过渡和动画效果之单元素/组件的过渡:别让你的网页动得像PPT!Vue过渡动画の魔术大揭秘

各位前端er!是不是经常被产品经理那句“这里能不能加点动效?”搞得头皮发麻?别慌,今天咱们就来聊聊Vue里的过渡和动画,保证让你从“动效小白”升级为“丝滑大师”!

先说实话:哪个用户不喜欢看丝滑的动效?就像喝奶茶要有珍珠,吃泡面要有火腿肠,网页没有过渡动画,总觉得少了点灵魂。但传统JS操作DOM实现动画简直反人类,好在Vue给我们准备了<transition>组件这个神器!

一、基础入门:让元素“淡入淡出”的魔法

想象一下,你要让一个div像幽灵一样缓缓出现又消失,用Vue有多简单?

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>淡入淡出示例</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <style>
    /* 进入和离开的激活期 */
    .fade-enter-active, .fade-leave-active {
      transition: opacity 0.5s ease;
    }
    /* 进入开始和离开结束的状态 */
    .fade-enter-from, .fade-leave-to {
      opacity: 0;
    }
  </style>
</head>
<body>
  <div id="app">
    <button @click="show = !show">
      {{ show ? '隐藏' : '显示' }}
    </button>
    
    <transition name="fade">
      <div v-if="show" class="demo-box">
        嘿,我淡入淡出给你看!
      </div>
    </transition>
  </div>
  <script>
    const { createApp } = Vue
    createApp({
      data() {
        return {
          show: true
        }
      }
    }).mount('#app')
  </script>
</body>
</html>

保存运行,点击按钮看看?是不是丝滑得让人感动?

核心原理揭秘:Vue在元素插入或移除时,自动添加/删除特定的CSS类名,就像给元素穿脱“隐身衣”:

  • v-enter-from:进入动画的起点(隐身状态)
  • v-enter-active:进入动画进行中(穿隐身衣的过程)
  • v-enter-to:进入动画的终点(完全现身)
  • v-leave-from:离开动画的起点(现身状态)
  • v-leave-active:离开动画进行中(脱隐身衣的过程)
  • v-leave-to:离开动画的终点(完全隐身)

注意上面代码中name="fade",这表示Vue会自动把类名前缀从v-换成fade-。如果你不写name,默认就是v-前缀。

二、进阶玩法:让动画更花里胡哨

只会淡入淡出太基础?来看看怎么让元素“蹦蹦跳跳”地出现:

<template>
  <div id="app">
    <button @click="show = !show">切换</button>
    
    <transition name="bounce">
      <div v-if="show" class="bounce-box">
        我弹,我弹,我弹弹弹!
      </div>
    </transition>
  </div>
</template>
<style>
.bounce-enter-active {
  animation: bounce-in 0.8s;
}
.bounce-leave-active {
  animation: bounce-in 0.8s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
  }
}
</style>

这个效果就像皮球落地一样,先压缩再弹起,最后稳定。是不是瞬间有内味了?

三、实战案例:购物车添加商品动画

光会基础可不够,来点实际的!比如那个经典的“商品飞入购物车”效果:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>购物车动画</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <style>
    .container {
      display: flex;
      justify-content: space-between;
      padding: 20px;
    }
    
    .product {
      width: 100px;
      height: 100px;
      background: #4CAF50;
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
    }
    
    .cart {
      width: 60px;
      height: 60px;
      background: #ff9800;
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50%;
      position: relative;
    }
    
    .cart-count {
      position: absolute;
      top: -10px;
      right: -10px;
      background: red;
      color: white;
      border-radius: 50%;
      width: 20px;
      height: 20px;
      font-size: 12px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .fly-enter-active {
      transition: all 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55);
    }
    
    .fly-enter-from {
      opacity: 0;
      transform: translateX(0) translateY(0) scale(1);
    }
    
    .fly-enter-to {
      opacity: 1;
      transform: translateX(200px) translateY(-100px) scale(0.5);
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="container">
      <div class="product" @click="addToCart">
        点击购买
      </div>
      
      <div class="cart">
        购物车
        <div class="cart-count">{{ count }}</div>
      </div>
    </div>
    
    <transition name="fly" @enter="onEnter">
      <div v-if="flying" class="product flying-item">+1</div>
    </transition>
  </div>
  <script>
    const { createApp } = Vue
    createApp({
      data() {
        return {
          count: 0,
          flying: false
        }
      },
      methods: {
        addToCart() {
          this.flying = true
          this.count++
        },
        onEnter() {
          setTimeout(() => {
            this.flying = false
          }, 800)
        }
      }
    }).mount('#app')
  </script>
</body>
</html>

这个例子中,点击商品时会创建一个“+1”元素,沿着曲线飞入购物车,同时购物车数量更新。用的cubic-bezier缓动函数让飞行轨迹更有“抛物体”的感觉。

四、终极武器:JavaScript钩子实现复杂动画

当CSS无法满足你的骚操作时,JavaScript钩子就该登场了!

<template>
  <div id="app">
    <button @click="show = !show">复杂动画切换</button>
    
    <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @after-enter="afterEnter"
      @enter-cancelled="enterCancelled"
      @before-leave="beforeLeave"
      @leave="leave"
      @after-leave="afterLeave"
      @leave-cancelled="leaveCancelled"
      :css="false"
    >
      <div v-if="show" class="js-animation-box">
        我被JS控制的!
      </div>
    </transition>
  </div>
</template>
<script>
import { gsap } from 'gsap' // 假设引入了GSAP动画库

export default {
  data() {
    return {
      show: false
    }
  },
  methods: {
    beforeEnter(el) {
      console.log('动画开始前:设置初始状态')
      el.style.opacity = 0
      el.style.transform = 'scale(0) rotate(0deg)'
    },
    
    enter(el, done) {
      console.log('进入动画进行中')
      gsap.to(el, {
        duration: 1,
        opacity: 1,
        scale: 1,
        rotation: 360,
        ease: 'back.out(1.7)',
        onComplete: done
      })
    },
    
    afterEnter(el) {
      console.log('进入动画完成')
    },
    
    enterCancelled(el) {
      console.log('进入动画被取消')
    },
    
    beforeLeave(el) {
      console.log('离开动画开始前')
    },
    
    leave(el, done) {
      console.log('离开动画进行中')
      gsap.to(el, {
        duration: 0.5,
        opacity: 0,
        scale: 0,
        rotation: -360,
        ease: 'power2.in',
        onComplete: done
      })
    },
    
    afterLeave(el) {
      console.log('离开动画完成')
    },
    
    leaveCancelled(el) {
      console.log('离开动画被取消')
    }
  }
}
</script>

这个例子展示了所有JavaScript钩子,用GSAP库实现了一个带弹性效果的旋转动画。注意:css="false"是告诉Vue“别插手CSS动画,全权交给JS处理”!

五、避坑指南与性能优化

动画虽好,可不要贪杯哦!以下几点一定要注意:

  1. 性能优先:尽量使用transformopacity做动画,这两个属性不会触发重排
  2. 硬件加速:可以尝试transform: translateZ(0)开启GPU加速
  3. 避免过度:不是所有东西都需要动画,关键操作反馈和状态变化就够了
  4. 移动端适配:移动设备性能有限,动画要更简洁

常见踩坑

  • 忘记写name属性,然后奇怪为什么CSS不生效
  • 没设置初始状态,动画直接从中间开始
  • 没调用done回调,导致钩子函数卡住
结语

好了,看到这里你已经掌握了Vue单元素/组件过渡动画的精髓!从基础的CSS过渡到复杂的JavaScript钩子,现在你完全可以在项目中大展身手了。

记住,好的动画应该是“润物细无声”的——用户可能说不出来哪里好,但就是觉得用着舒服。就像那句老话:最好的界面是用户感觉不到的界面。

快去给你的网页加点魔法吧!如果还有问题,Vue官方文档永远是你最好的朋友(虽然有时候有点难懂,但现在你应该都能看明白了)!

彩蛋:试试把今天学到的技术组合使用,比如先CSS过渡再JS动画,或者给不同状态设置不同的缓动函数,说不定能创造出下一个让人惊艳的动效呢!


附:完整示例代码合集
本文所有示例均可直接复制到HTML文件中运行,建议边看边动手试试。动画这东西,光看不练假把式,动手敲一遍,理解更深!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值