>  기사  >  웹 프론트엔드  >  Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

青灯夜游
青灯夜游앞으로
2022-09-09 20:39:432452검색

Vue는 애니메이션 효과를 쉽게 얻을 수 있도록 많은 애니메이션 인터페이스를 제공합니다. 전환 애니메이션은 몇 가지 간단한 애니메이션을 구현할 수 있습니다. 애니메이션에 여러 개의 간단한 애니메이션이 포함되어 있으면 애니메이션 후크를 사용해야 합니다. 이 문서에는 일상적인 개발에서 자주 접할 수 있는 몇 가지 예가 나열되어 있습니다.

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

ToC 프로젝트를 개발할 때 일반적인 라우팅 애니메이션, 팝업 상자 애니메이션, 일부 비즈니스 애니메이션 등 많은 애니메이션을 사용해야 합니다. 이 문서에서는 향후 검토를 용이하게 하기 위해 학습한 애니메이션을 요약합니다. 도움이 되셨다니 영광입니다.

먼저 원하는 애니메이션 효과를 빠르게 얻을 수 있도록 Vue에서 제공하는 애니메이션을 검토해 보겠습니다. [관련 권장사항: vuejs 비디오 튜토리얼Vue 提供了那些动画,帮助我们快速实现想要的动画效果。【相关推荐:vuejs视频教程

Vue 动画

CSS 过渡

以显示和隐藏动画为例:

<div>
  <button>
    Toggle
  </button>
  <transition>
    <p>hello</p>
  </transition>
</div>

从隐藏到显示

当动画开始的时候,P 标签还是隐藏的,此时 Vue 会给 P 加上两个class:

.fade-enter {
   opacity: 0;
}
.fade-enter-active {
   transition: opacity 0.5s;
}

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

当动画开始后,会移除.fade-enter(在元素被插入之前生效,在元素被插入之后的下一帧移除),这个时候 P 标签的 opacity就恢复到 1,即显示,这个时候就会触发transition , 检测到opacity的变化,就会产生动画。当动画结束后,会移除 Vue 加上的 class(v-enter-to, v-enter-active)。

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

上面这个过程是怎么实现的呢?它主要用到了requestAnimationFrame这个api,我们自己可以实现一个简易版的动画,当生成下一帧的时候添加或删除某个类,从而形成动画效果。

nbsp;html>

  
    <title>Document</title>
    <style>
      .box {
        width: 100px;
        height: 100px;
        background-color: red;
      }
      .enter {
        opacity: 0;
      }
      .mov {
        transition: opacity 5s linear;
      }
    </style>
  
  
    <div></div>
    <script>
      var box = document.getElementById(&#39;box&#39;)
      // 第一帧之后执行
      requestAnimationFrame(function() {
        box.setAttribute(&#39;class&#39;, &#39;box mov&#39;)
      })
    </script>
  

当生成下一帧的时候,会移除enter这个class,那么 div 就会显示出来,就会触发transition产生动画效果。

从显示到隐藏

当隐藏的时候也产生动画,如下图:

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

.fade-leave-to {
   opacity: 0;
}
.fade-leave-active {
   transition: opacity 0.5s;
}

刚开始 P 标签是显示的,因为此时fade-leave (在离开过渡被触发时立刻生效,下一帧被移除) 的样式是 opacity 是 1,执行到第二帧的时候加上fade-leave-to(在离开过渡被触发之后下一帧生效 ,与此同时 fade-leave 被删除),此时opacity 是 0,既然发生了属性的变化,transition就会监听到,从而形成动画。

这样显示和隐藏就形成了一个完整的动画。

原理是当你通过点击事件改变css属性,比如opacity时,transition会检测到这个变化,从而形成动画

CSS 动画

CSS 动画原理同 CSS 过渡类似,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。

<style>
  .bounce-enter-active {
    animation: bounce-in 3s;
  }
  .bounce-leave-active {
    animation: bounce-in 3s reverse;
  }
  @keyframes bounce-in {
    0% {
      transform: scale(0);
    }
    50% {
      transform: scale(1.5);
    }
    100% {
      transform: scale(1);
    }
  }
</style>

<div>
  <button>Toggle show</button>
  <transition>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris
      facilisis enim libero, at lacinia diam fermentum id. Pellentesque
      habitant morbi tristique senectus et netus.
    </p>
  </transition>
</div>

当我们点击改变showfalse时,会在 P 标签上添加.bounce-leave-active这个class,这个类就会执行animation 动画,当动画执行完成后删除.bounce-leave-active

JavaScript 钩子动画

nbsp;html>

  
    ...
    <script></script>
    <script></script>
  
  
    <div>
      <button>
        Toggle
      </button>
      <transition>
        <p>
          Demo
        </p>
      </transition>
    </div>

    <script>
      new Vue({
        el: &#39;#demo&#39;,
        data: {
          show: true
        },
        methods: {
          beforeEnter: function(el) {
            el.style.opacity = 0
            el.style.transformOrigin = &#39;left&#39;
          },
          enter: function(el, done) {
            Velocity(el, { opacity: 1, fontSize: &#39;1.4em&#39; }, { duration: 1000 })
            Velocity(el, { fontSize: &#39;1em&#39; }, { complete: done })
          },
          leave: function(el, done) {
            Velocity(
              el,
              { translateX: &#39;15px&#39;, rotateZ: &#39;50deg&#39; },
              { duration: 600 }
            )
            Velocity(
              el,
              {
                rotateZ: &#39;45deg&#39;,
                translateY: &#39;30px&#39;,
                translateX: &#39;30px&#39;,
                opacity: 0
              },
              { complete: done }
            )
          }
        }
      })
    </script>
  
  • before-enter: 是指在动画之前执行的函数;

  • enter: 就是整个动画的过程, 执行完后要加一个done(),来告诉vue已经执行完毕;当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

  • after-enter: 动画结束之后执行;

Javascript 钩子动画一般用在比较复杂的动画上,而不是简单的过渡动画。后面我们会用很大的篇幅通过几个例子来说明用 Javascript 钩子动画是如何完成复杂动画的。

初始渲染的过渡

因为CSS过渡动画需要有个触发条件,比如opacity必须有一个变化,如果没有变化就不会触发。那么,可以通过 appear]

Vue 애니메이션

CSS 전환

을 표시하고 숨겨진 애니메이션의 예:

<transition>
    <!-- ... -->
</transition>

숨기기에서 표시까지

애니메이션이 시작되면 P 태그는 여전히 숨겨져 있고 Vue 두 개의 클래스가 P:🎜
<transition>
    <!-- ... the buttons ... -->
</transition>
🎜에 추가됩니다. Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제🎜🎜애니메이션이 시작되면 .fade-enter가 제거됩니다(요소가 삽입되기 전에 유효하고 요소가 삽입된 후 다음 프레임에서 제거됩니다). 이때, P 태그의 불투명도는 1로 복원됩니다. 즉, 불투명도가 변경되면 <code>전환이 시작됩니다. 가 감지되었습니다. 애니메이션입니다. 애니메이션이 끝나면 Vue에서 추가한 클래스(v-enter-to, v-enter-active)가 제거됩니다. 🎜🎜Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제🎜🎜위 이 프로세스는 어떻게 달성됩니까? 주로 requestAnimationFrame API를 사용하여 간단한 애니메이션 버전을 직접 구현하고, 다음 프레임을 생성할 때 클래스를 추가하거나 삭제하여 애니메이션 효과를 만들 수 있습니다. 🎜
<div>
  <div>
    <button>
      Toggle
    </button>
  </div>

  <transition>
    // 一定要设置key
    <div>
      if Demo
    </div>
    <div>else demo</div>
  </transition>
</div>

<style>
  .cls {
    display: inline-block;
  }
  .fade-enter-active,
  .fade-leave-active {
    transition: all 1s;
    // 这个定位设置很关键
    position: absolute;
  }

  .fade-enter {
    opacity: 0;
    transform: translateX(30px);
  }

  .fade-leave-to {
    opacity: 0;
    transform: translateX(-30px);
  }
</style>
🎜다음 프레임이 생성되면 enter 클래스가 제거되고 div가 표시되며 transition이 트리거되어 애니메이션 효과가 생성됩니다. 🎜

표시에서 숨기기까지

🎜숨길 때도 아래와 같이 애니메이션이 생성됩니다. 🎜🎜Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제🎜
<transition>
    <component></component>
</transition>

new Vue({
  el: '#transition-components-demo',
  data: {
    view: 'v-a'
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>'
    },
    'v-b': {
      template: '<div>Component B</div>'
    }
  }
})

.component-fade-enter-active, .component-fade-leave-active {
  transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to {
  opacity: 0;
}
🎜이 때문에 처음에는 P 태그가 표시됩니다. fade-leave(나가기 전환이 트리거될 때 즉시 적용되고 다음 프레임에서 제거됨)인 경우 스타일은 1이고 실행 시 추가되는 불투명도입니다. 두 번째 프레임 fade-leave-to(나가기 전환이 트리거된 후 다음 프레임에 적용되고 동시에 fade-leave가 삭제됨) 이때 불투명도 코드>는 0입니다. 속성이 변경되므로 전환이 이를 모니터링하여 애니메이션을 형성합니다. 🎜🎜이렇게 표시하고 숨기면 완전한 애니메이션이 됩니다. 🎜🎜원칙은 클릭 이벤트를 통해 불투명도와 같은 CSS 속성을 변경하면 전환이 변경 사항을 감지하고 애니메이션을 형성한다는 것입니다.. 🎜

CSS 애니메이션

🎜 CSS 애니메이션의 원리는 CSS 전환과 유사하지만 차이점은 애니메이션에서는 v-enter입니다. 클래스 이름은 노드 뒤에 DOM에 삽입됩니다. 즉시 삭제되지는 않지만 animationend 이벤트가 트리거되면 삭제됩니다. 🎜
<transition>
  // 这里加了key
  <router-view>
</router-view></transition>

computed: {
  key() {
      return this.$route.path
  }
}

.fade-transform-leave-active,
.fade-transform-enter-active {
    transition: all 0.5s;
}

.fade-transform-enter {
    opacity: 0;
    transform: translateX(-30px)
}

.fade-transform-leave-to {
    opacity: 0;
    transform: translateX(30px)
}
🎜showfalse로 변경하기 위해 클릭하면 .bounce-leave-active 클래스가 P 태그에 추가됩니다. class 애니메이션 애니메이션이 실행되며, 애니메이션이 완료되면 .bounce-leave-active가 삭제됩니다. 🎜

JavaScript 후크 애니메이션

<div>
  <transition>
    // 外面一层遮罩
    <div>
      // 这里面才是内容
      <div></div>
    </div>
  </transition>

  <div>
    Add
  </div>
</div>

<style>
  .add {
    position: fixed;
    bottom: 0;
    left: 0;
    text-align: center;
    line-height: 40px;
  }

  .playlist {
    position: fixed;
    z-index: 200;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0, 0, 0, 0.3);
  }
  .list-wrapper {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 400px;
    background-color: #333;
  }
  
  // 针对最外面一层的遮罩
  .list-fade-enter-active,
  .list-fade-leave-active {
    transition: opacity 0.3s;
  }
  // 针对类为list-wrapper的内容
  .list-fade-enter-active .list-wrapper,
  .list-fade-leave-active .list-wrapper {
    transition: all 0.3s;
  }
  
  .list-fade-enter,
  .list-fade-leave-to {
    opacity: 0;
  }
  
  // 最开始内容是隐藏的,所以translate3d(0, 100%, 0)
  .list-fade-enter .list-wrapper,
  .list-fade-leave-to .list-wrapper {
    transform: translate3d(0, 100%, 0);
  }
</style>
  • 🎜before-enter: 애니메이션 전에 실행되는 함수를 나타냅니다. 🎜
  • 🎜enter: 전체 애니메이션 프로세스입니다. 실행 후 전환에 JavaScript만 사용하는 경우 실행이 완료되었음을 vue에 알리기 위해 done()을 추가해야 하며 콜백에는 done을 사용해야 합니다. Enter 및 Leave 에서. 그렇지 않으면 동기적으로 호출되고 전환이 즉시 완료됩니다. 🎜
  • 🎜after-enter: 애니메이션이 끝난 후 실행됩니다. 🎜
🎜자바스크립트 후크 애니메이션은 일반적으로 단순한 전환 애니메이션보다는 더 복잡한 애니메이션에 사용됩니다. 강하다>. 나중에 우리는 Javascript 후크 애니메이션을 사용하여 복잡한 애니메이션을 완성하는 방법을 여러 예제를 통해 설명하기 위해 많은 공간을 사용할 것입니다. 🎜

초기 렌더링 전환

🎜CSS 전환 애니메이션에는 불투명도와 같은 트리거 조건이 있어야 하기 때문입니다. 변경 사항이 없으면 트리거되지 않는 변경 사항이 있어야 합니다. 그런 다음 appear 속성을 ​​통해 초기 렌더링에서 노드의 전환을 설정할 수 있습니다. 🎜
<div>
  <transition-group>
    <li>
      <span></span>
      <span>
        delete
      </span>
    </li>
  </transition-group>
</div>

.item {
  height: 40px;
}
.list-enter-active,
.list-leave-active {
  transition: all 0.1s
}
.list-enter,
.list-leave-to {
  height: 0
}
🎜🎜CSS 애니메이션(애니메이션)에는 트리거 조건이 필요하지 않습니다. 🎜

多个元素的过渡

一旦涉及到多个元素的过渡,那么就会出现旧元素和新元素进出的先后问题。<transition></transition> 的默认行为是进入和离开同时发生,但是这样就会产生一些不协调的效果,所以 Vue 提供了过渡模式

  • in-out:新元素先进行过渡,完成之后当前元素过渡离开(in-out 模式不是经常用到,但对于一些稍微不同的过渡效果还是有用的)。
  • out-in:当前元素先进行过渡,完成之后新元素过渡进入(这个用的比较多)。
<transition>
    <!-- ... the buttons ... -->
</transition>

但是这两个模式并不能完全满足实际需要,实际上我们可以定制我们要想的先后效果,比如后台管理系统中有一个面包屑导航栏,当改变路由的时候需要更改面包屑里面的内容,那么这个更改的动画可以让旧的元素向左滑出,新的元素从右边滑入。

<div>
  <div>
    <button>
      Toggle
    </button>
  </div>

  <transition>
    // 一定要设置key
    <div>
      if Demo
    </div>
    <div>else demo</div>
  </transition>
</div>

<style>
  .cls {
    display: inline-block;
  }
  .fade-enter-active,
  .fade-leave-active {
    transition: all 1s;
    // 这个定位设置很关键
    position: absolute;
  }

  .fade-enter {
    opacity: 0;
    transform: translateX(30px);
  }

  .fade-leave-to {
    opacity: 0;
    transform: translateX(-30px);
  }
</style>

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

当有相同标签名的元素切换时,需要通过 key attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在 transition 组件中的多个元素设置 key 是一个更好的实践。

多个组件的过渡

多个组件的过渡简单很多 - 我们不需要使用 key attribute。相反,我们只需要使用动态组件

<transition>
    <component></component>
</transition>

new Vue({
  el: '#transition-components-demo',
  data: {
    view: 'v-a'
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>'
    },
    'v-b': {
      template: '<div>Component B</div>'
    }
  }
})

.component-fade-enter-active, .component-fade-leave-active {
  transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to {
  opacity: 0;
}

列表过渡

上面讲的动画都是针对单个节点,或者同一时间渲染多个节点中的一个,那么怎么同时渲染整个列表,比如使用 v-for

在这种场景中,使用 <transition-group></transition-group> 组件,这个组件的几个特点:

  • 不同于 <transition></transition>,它会以一个真实元素呈现:默认为一个 <span></span>。你也可以通过 tag attribute 更换为其他元素。
  • 过渡模式不可用,因为我们不再相互切换特有的元素。
  • 内部元素总是需要提供唯一的 key attribute 值。
  • CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。

后面我们会通过一个例子演示如何使用<transition-group></transition-group> 。

案例

路由动画

在后台管理系统中,当路由变化时,对应的组件内容也会发生变化,当在变化时加上一个动画,让整个页面效果更加自然。

<transition>
  // 这里加了key
  <router-view>
</router-view></transition>

computed: {
  key() {
      return this.$route.path
  }
}

.fade-transform-leave-active,
.fade-transform-enter-active {
    transition: all 0.5s;
}

.fade-transform-enter {
    opacity: 0;
    transform: translateX(-30px)
}

.fade-transform-leave-to {
    opacity: 0;
    transform: translateX(30px)
}

H5 页面弹框从底部弹出动画

在 H5 页面开发中,一个常用的功能是点击一个按钮,隐藏的内容从屏幕底部弹出,同时弹出的时候有个动画效果,一般是缓慢上升。

<div>
  <transition>
    // 外面一层遮罩
    <div>
      // 这里面才是内容
      <div></div>
    </div>
  </transition>

  <div>
    Add
  </div>
</div>

<style>
  .add {
    position: fixed;
    bottom: 0;
    left: 0;
    text-align: center;
    line-height: 40px;
  }

  .playlist {
    position: fixed;
    z-index: 200;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0, 0, 0, 0.3);
  }
  .list-wrapper {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 400px;
    background-color: #333;
  }
  
  // 针对最外面一层的遮罩
  .list-fade-enter-active,
  .list-fade-leave-active {
    transition: opacity 0.3s;
  }
  // 针对类为list-wrapper的内容
  .list-fade-enter-active .list-wrapper,
  .list-fade-leave-active .list-wrapper {
    transition: all 0.3s;
  }
  
  .list-fade-enter,
  .list-fade-leave-to {
    opacity: 0;
  }
  
  // 最开始内容是隐藏的,所以translate3d(0, 100%, 0)
  .list-fade-enter .list-wrapper,
  .list-fade-leave-to .list-wrapper {
    transform: translate3d(0, 100%, 0);
  }
</style>

这个动画有两层,一层是最外层的内容,另一层是最里面部分的内容,效果如下:

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

列表删除动画

在 H5 页面开发中,如果在一个列表页中删除其中一个子项,要求有一个删除动画效果。

<div>
  <transition-group>
    <li>
      <span></span>
      <span>
        delete
      </span>
    </li>
  </transition-group>
</div>

.item {
  height: 40px;
}
.list-enter-active,
.list-leave-active {
  transition: all 0.1s
}
.list-enter,
.list-leave-to {
  height: 0
}

复杂动画-案例1

看下面的图片,这个动画该怎么实现呢?

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

一般复杂的动画,并不能用简单的 css 过渡或者 css 动画能实现的,需要使用 javascript钩子动画实现。

针对上面图片的动画进行拆解:

  • 当从底部谈起的时候,页面顶部(向下的箭头和歌曲名称部分)从上往下滑入,同时有个回弹的效果,同时,底部(播放进度条的部分)从下往上滑入,也有一个回弹的效果。

  • 左下角旋转的圆有两个动画效果,一个是从小变大,一个是从左下角滑动到中心部分

  • 圆的旋转动画

代码结构:

<div>
    <transition>
      <div>
        <div>
          // 顶部区域...
        </div>
        <div>
          // 中间区域...   
        </div>
        <div>
          // 底部区域...
        </div>
      </div>
    </transition>
    <transition>
      <div>
         // 内容区域...  
      </div>
    </transition>
</div>

实现第一个动画效果

// 这是stylus的写法
.normal-enter-active,
.normal-leave-active
  transition: all 0.4s
  .top,
  .bottom
    // 通过这个白塞尔曲线,使得动画有个回弹的效果
    transition: all 0.4s cubic-bezier(0.86, 0.18, 0.82, 1.32)
.normal-enter,
.normal-leave-to
  opacity: 0
  .top
    // 从上往下滑入
    transform: translate3d(0, -100px, 0)
  .bottom
    // 从下往上滑入
    transform: translate3d(0, 100px, 0)

通过第一章节部分的学习,看懂这段动画代码应该不难。

实现第二个动画效果

要实现这个动画效果,必须要计算左下角的圆到中心部分的圆的 x 轴和 y 轴方向上的距离,因为H5页面在不同的手机屏幕下,这个距离是不同的,所以一开始就不能写死,只能通过 javascript 去动态的获取。

// 计算从小圆中心到大圆中心的距离以及缩放比例
_getPosAndScale() {
  const targetWidth = 40
  const paddingLeft = 40
  const paddingBottom = 30
  const paddingTop = 80
  const width = window.innerWidth * 0.8
  const scale = targetWidth / width
  const x = -(window.innerWidth / 2 - paddingLeft)
  const y = window.innerHeight - paddingTop - width / 2 - paddingBottom
  return {
    x,
    y,
    scale
  }
}

这段代码细节可以不用看,只需要知道它是计算左下角小圆的原心到中心部分圆的原心的距离(x, y),以及根据圆的直径获取放大缩小倍数(scale)。

// 这个库可以让我们使用js来创建一个keyframe的动画,为什么要用js来生成呢?这是因为有些变化的属性需要动态的计算,而不是一开始就定好了
import animations from 'create-keyframe-animation'


// 动画钩子
// done:当动画执行完后执行done函数,然后跳到afterEnter钩子函数
enter(el, done) {
  const { x, y, scale } = this._getPosAndScale()
  // 对于大圆来说,进入的时机就是从小圆到小圆
  let animation = {
    0: {
      // 一开始大圆相对于小圆的位置,所以x为负数,y为整数
      transform: `translate3d(${x}px, ${y}px, 0) scale(${scale})`
    },
    // scale: 1.1 这样圆就有个放大后变回原样的效果
    60: {
      transform: 'translate3d(0, 0, 0) scale(1.1)'
    },
    100: {
      transform: 'translate3d(0, 0, 0) scale(1)'
    }
  }
  // 设置animation
  animations.registerAnimation({
    name: 'move',
    animation,
    presets: {
      duration: 400,
      easing: 'linear'
    }
  })
  // 往dom上加上这个animation,并执行动画
  animations.runAnimation(this.$refs.cdWrapper, 'move', done)
},
// 动画结束之后把样式置为空
afterEnter() {
  animations.unregisterAnimation('move')
  this.$refs.cdWrapper.style.animation = ''
},
leave(el, done) {
  this.$refs.cdWrapper.style.transition = 'all 0.4s'
  const { x, y, scale } = this._getPosAndScale()
  this.$refs.cdWrapper.style[
    transform
  ] = `translate3d(${x}px,${y}px,0) scale(${scale})`
  // 这样写的目的是如果没有监听到动画结束的事件,那么我们自己就写一个定时器,400ms后执行done函数
  const timer = setTimeout(done, 400)
  // 监听动画结束
  this.$refs.cdWrapper.addEventListener('transitionend', () => {
    clearTimeout(timer)
    done()
  })
}

这段代码的效果就是大圆的动画效果。当点击小圆的时候,大圆开始进入,进入的过程就是动画的过程。当点击向下的箭头,大圆将消失,消失的过程就是大圆退出的动画过程。

虽然有点复杂,但是也不难看懂,以后我们对于复杂动画可以模仿上面的代码。

那小圆的动画呢?它非常简单,就是一个显示隐藏的动画:

.mini-enter-active,
.mini-leave-active
  transition: all 0.4s
.mini-enter,
.mini-leave-to
  opacity: 0

至此,就完成小圆和大圆的联动动画,整体效果还是很惊艳的。

实现第三个动画

// 模板部分
<div>
  <img  alt="Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제" >
</div>

// 逻辑部分
// 通过事件来控制playing的值,然后改变img标签的class,从而是动画停止和展示
cdCls() {
   return this.playing ? 'play' : 'play pause'
}

// css部分
.play
  animation: rotate 20s linear infinite
.pause
  animation-play-state: paused
  
@keyframes rotate
  0%
    transform: rotate(0)
  100%
    transform: rotate(360deg)

复杂动画-案例2

Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제

首先对动画进行拆解:

  • 当点击 + 的时候,有一个小圆从右侧向xiang左侧滚动出来到指定的位置,既有滚动的效果,也有从右往左移动的效果。同时,当点击 - 的时候,小圆从左侧滚动到右侧并消失。

  • 当点击 + 的时候,会出现一个小球,这个小球会从点击的位置做一个抛物线运动轨迹到左下角的购物车中。同时,当我连续点击的时候,会出现多个小球同时做抛物线运行出现在屏幕中。

实现第一个动画

通过上面的学习,对这一个动画的实现应该不难。代码如下:

<div>
  // 小圆 - 
  <transition>
    <div>0" @click.stop="decrease">
      <span> - </span>
    </div>
  </transition>
  <div>0">{{food.count}}</div>
  // 小圆 + 
  <div> + </div>
</div>

.move-enter-active, &.move-leave-active
  transition: all 0.4s linear
.move-enter, &.move-leave-active
  // 外层动画是从右往左运动
  opacity: 0
  transform: translate3d(24px, 0, 0)
  .inner
    // 内层动画是旋转180°
    transform: rotate(180deg)

实现第二个动画

  • 创建小球,因为这个动画就是对小球的动画

<div>
  <div>
    <transition>
      <div>
        <div></div>
      </div>
    </transition>
  </div>
</div>

<script>
function createBalls() {
  let balls = []
  for (let i = 0; i < BALL_LEN; i++) {
    balls.push({ show: false })
  }
  return balls
}

data() {
  return {
    balls: createBalls()
  }
},  
</script>

这里创建是10个小球,小球开始的状态都是隐藏的。

  • 点击 + 按钮的时候,触发一个小球弹出

// 点击加号调用这个函数,同时把加号的dom传递,这样就能知道小球运动的起点位置
onAdd(target) {
  // shopCart就是图中底部组件,执行drop函数
  this.$refs.shopCart.drop(target)
},

// 把加号对应的dom传入,并绑定到小球el属性上
drop(el) {
  for (let i = 0; i <p>因为小球的<code>ball.show</code>为true,那么就会触发对应的动画钩子函数,首先触发<code>beforeDrop</code>:</p><pre class="brush:php;toolbar:false">beforeDrop(el) {
  // 取出最后一个小球
  const ball = this.dropBalls[this.dropBalls.length - 1]
  // 获取小球的起点位置,就是在哪个地方点击的加号按钮
  const rect = ball.el.getBoundingClientRect()
  const x = rect.left - 32
  const y = -(window.innerHeight - rect.top - 22)
  // 设置小球的位置,把小球设置到点击加号按钮的那个地方
  el.style.display = ''
  // 外层动画,向下
  el.style.transform = el.style.webkitTransform = `translate3d(0,${y}px,0)`
  const inner = el.getElementsByClassName(innerClsHook)[0]
  // 内层动画向左
  inner.style.transform = inner.style.webkitTransform = `translate3d(${x}px,0,0)`
}

接着执行enter事件函数dropping:

dropping(el, done) {
  // 触发浏览器重绘,把beforeDrop事件中设置的小球位置从底部位置移动到点击加号的位置,这样小球就会从上面往下面落下
  this._reflow = document.body.offsetHeight
  // 设置小球落下的终点位置
  el.style.transform = el.style.webkitTransform = `translate3d(0,0,0)`
  const inner = el.getElementsByClassName(innerClsHook)[0]
  inner.style.transform = inner.style.webkitTransform = `translate3d(0,0,0)`
  // 监听动画结束
  el.addEventListener('transitionend', done)
}

最后执行after-enter事件函数afterDrop:

afterDrop(el) {
  // 取出第一个小球,设置属性show为false,同时要设置el.style.display = 'none'
  const ball = this.dropBalls.shift()
  if (ball) {
    ball.show = false
    el.style.display = 'none'
  }
}

我们来梳理下流程:

  • 点击加号位置,触发drop函数,然后把一个隐藏的小球设置为显示状态,存储在dropBalls中,因为用户可以快速点击,所以dropBalls里面可能有多个小球。

  • 当把小球状态设置为显示状态,就会触发动画钩子before-enter,enter,after-enter这三个钩子。

  • before-enter的作用是把小球的位置设置到点击的位置,同时利用offsetHeight触发浏览器重绘,这样就会把小球的位置放在点击的位置。

  • enter的作用就是让小球从点击的位置落下,动画分为两层,一层是向下,另一层是向左,当两者结合就构成了一个从右上角到左下角斜线的动画轨迹,但是一个斜的直线动画轨迹比较丑,这里就使用了时间函数cubic-bezier来改变动画轨迹,使其有一个先向上运动,最后向下运动的抛物线轨迹动画。

.ball
  position: fixed
  left: 32px
  bottom: 22px
  z-index: 200
  transition: all 0.4s cubic-bezier(0.49, -0.29, 0.75, 0.41)
  .inner
    width: 16px
    height: 16px
    border-radius: 50%
    background: $color-blue
    transition: all 0.4s linear
  • after-enter当小球到达目的后,需要把小球隐藏起来,所以取出第一个小球,然后设置show的属性为false,这样小球就隐藏起来,等待下一次动画执行。

所以函数的执行顺序是:drop -> before-enter -> enter -> after-enter -> drop -> before-enter -> enter -> after-enter...,这样就形成了在页面中同时出现多个小球的动画。

注意:当我们设置show的属性为false就可以了,但是代码中同时也设置了el.style.display = 'none',如果不设置这个小球消失有一个延迟。

好了,整个 Vue 动画到此就结束了,动画其实是一个比较难的功能,特别是复杂动画。通过上面两个复杂动画可以给我们做一个借鉴,相信你也能写出自己想要的动画效果。

(학습영상 공유: 웹 프론트엔드 개발, 기본 프로그래밍 영상)

위 내용은 Vue 애니메이션을 플레이하는 데 도움이 되는 자세한 예제의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제