安装
cnpm install wowjs -S
- 根组件加入animate.css 的CDN
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css" />
使用
- 封装util注册方法
import { onMounted } from 'vue'
import { WOW } from 'wowjs'
// wow swing
export default () => {
onMounted(() => {
var wow = new WOW({
boxClass: 'wow', // animated element css class (default is wow)
animateClass: 'animated', // animation css class (default is animated)
offset: 0, // distance to the element when triggering the animation (default is 0)
mobile: true, // trigger animations on mobile devices (default is true)
live: true, // act on asynchronously loaded content (default is true)
callback: function (box) {
},
scrollContainer: null, // optional scroll container selector, otherwise use window,
resetAnimation: true // reset animation on end (default is true)
})
wow.init()
})
}
- 组件中使用
-
- data-wow-duration 设置动画时间
-
- data-wow-delay 设置延迟时间
-
- wow 类名必须加上,bounceInLeft为animate.css的动画类名
<template>
<div class="wow bounceInLeft" data-wow-duration="3s" data-wow-delay="0s"></div>
<div class="wow bounceInLeft" data-wow-duration="3s" data-wow-delay="0s"></div>
</template>
<script setup>
import wow from '@/utils/wow.js'
wow()
</script>
原理解析
提出问题 :
- 如何做到滚动到元素位置,触发事件?
- 触发事件后如何做到配合animate.css来使用?
问题1 如何做到滚动到元素位置,触发事件?
要知道当前元素是否在可是区域, 其实和 图片懒加载这个原理是一模一样的。
方式1, 使用 IntersectionObserver API
简单来说就是,当绑定的元素达到可以区域内能执行事件。
const io = new IntersectionObserver(entries => {
if(entries[0].isIntersecting){
// 代表到了可视区域
}
});
// 绑定对应监听的元素
io.observe(el);
方式2,原生方法
通过 el.getBoundingClientRect(),clientHeight, scrollTop 等等自己去算当前是否在可视区域内。 注意要使用节流哦!!
问题2 触发事件后如何做到配合animate.css来使用?
问题1中已经解决了触发时机, 那么方法该如何写呢?
- 我们先来讲解一下animate.css 基本设计原理。看如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>animate learn</title>
<style lang="less">
@keyframes bounce {
from,
20%,
53%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
40%,
43% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -30px, 0) scaleY(1.1);
}
70% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -15px, 0) scaleY(1.05);
}
80% {
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translate3d(0, 0, 0) scaleY(0.95);
}
90% {
transform: translate3d(0, -4px, 0) scaleY(1.02);
}
}
.animate
{
animation: bounce 2s;
/* transform-origin: center bottom; */
}
#main{
width: 100px;
height: 100px;
position: absolute;
top: 10%;
font-size: 40px;
}
</style>
</head>
<body>
<div id="main">animate.css</div>
<button id="active">test</button>
</body>
<script>
const animateCSS=(element,animationName)=>{
new Promise((resolve,reject)=>{
const node=document.querySelector(element);
console.dir(node)
node.classList.add(animationName);
// When the animation ends, we clean the classes and resolve the Promise
function handleAnimationEnd(event)
{
event.stopPropagation();
node.classList.remove(animationName);
resolve('animation end');
}
node.addEventListener('animationend', handleAnimationEnd, {once: true});
})
}
const acticeButton=document.querySelector("#active");
acticeButton.addEventListener('click',()=>{
animateCSS('#main','animate')
})
</script>
</html>
总结: 触发机制就是, 手动给元素绑定类名, 当动画执行完成以后把类名取消掉即可。