JavaScript 练手小技巧:animationend 事件及其应用小案例

本文介绍了如何利用CSS动画和`animationend`事件创建各种动态效果,包括元素的显隐切换、多元素的轮播动画以及带退出动画的轮播。通过案例展示了CSS关键帧动画、事件监听以及JavaScript操作DOM实现动态效果的方法。
摘要由CSDN通过智能技术生成

animationend 事件在 CSS 动画完成后触发。

CSS 动画播放时,会发生以下三个事件:

  1. animationstart - CSS 动画开始后触发
  2. animationiteration - CSS 动画重复播放时触发
  3. animationend - CSS 动画完成后触发

在这三个事件函数中,均可以使用 event.animationName 属性,判断是在执行哪个动画。

个人觉得 animationend 事件用的多一点。

案例1:标签的隐现

<button type="button" id="btn">点击</button>
<div class="box" id="box"></div>
.box{
    width: 100px;
    height: 100px;
    background: #f00;
    display: none;
    margin-left: auto;
    margin-right: auto;
}
.box.show{
    display: block;
}
@keyframes showAni {
    0%{
        opacity: 0;
    }
    100%{
        opacity: 1;
    }
}
@keyframes hideAni {
    0%{
        opacity: 1;
    }
    100%{
        opacity: 0;
    }
}
  •  默认 div.box 是隐藏的。
  • 点击按钮,让 div.box 显示;但是动画效果全部由 CSS 的 keyframes 去完成。
  • 显示的动画很简单,让 div.box 显示的同时,执行 animation 动画就行。显示利用了 类 show 去执行,好处是可以判断 div.box 是执行显示效果,还是执行隐藏效果。
  • 但是隐藏的时候,要先执行动画,当动画完毕的时候,再利用 animationend 事件函数,让 div.box 隐藏。
let btn = document.getElementById("btn");
let box = document.getElementById("box");
btn.addEventListener("click",function(){
        if( !box.classList.contains("show") ){ // 如果 box 不包含 类show,说明需要显示它。
            box.classList.add("show");
            box.style.animation = "showAni  0.5s  both";
        }else{   // 否则就要隐藏
            box.style.animation = "hideAni  0.5s  both";
        }
});
// 隐藏动画完毕时,就要去掉 show 的类。
box.addEventListener("animationend",function(event){
       if(event.animationName === "hideAni" ){
           box.classList.remove("show");
       }
});

案例2:多个标签的隐现

<div style="text-align:center;">
    多个标签的动画显示和隐藏
    <button type="button" id="btn">点击</button>
</div>
<div class="box" id="box">
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
</div>
*{
    margin: 0;
    padding: 0;
}
ul,li,ol{
    list-style-type: none;
}

.box{
    width: 100px;
    height: 100px;
    display: none;
    perspective: 500px;
    margin-left: auto;
    margin-right: auto;
}
.box li{
    background: #f00;
}
.box.show{
    display: block;
}
@keyframes showAni {
    0%{
        opacity: 0;
        transform: rotateY(90deg);
    }
    100%{
        opacity: 1;
        transform: rotateY(0deg);
    }
}
@keyframes hideAni {
    0%{
        opacity: 1;
        transform: rotateY(0deg);
    }
    100%{
        opacity: 0;
        transform: rotateY(90deg);
    }
}

整体思路,跟前面的很类似。

不过,这次的动画是直接写在 每个 li 上面,而不是 div.box 整体。因此,显示的时候,要对 li 遍历,依次开展动画;隐藏的时候,也是同理。

在多个标签隐藏时候,要用到 setTimeout,等待所有动画执行完毕后,才去掉 div.box 的类 show。

let btn = document.getElementById("btn");
let box = document.getElementById("box");
btn.addEventListener("click",function(){
    let li = box.querySelectorAll("li");  // 获取所有的 li 标签
    if( !box.classList.contains("show") ){
        box.classList.add("show");
        li.forEach(function(value, key, parent){
            value.style.animation =`showAni 0.2s ${0.2*key}s both`;
        });
    }else{
        // for(let i=li.length-1; i>=0 ; i--){
        //     li[i].style.animation =`hideAni 0.2s ${0.2*(li.length-1-i)}s both`;
        // }
        li.forEach(function(value, key, parent){
            value.style.animation =`hideAni 0.2s ${0.2*(li.length-1-key)}s both`;
        });
        setTimeout(function(){
            box.classList.remove("show");
        },200*(li.length-1));  // 等待所有动画执行完毕,去掉 box 的show类。
    }
});

案例3:图片轮播

这个效果应该被写滥了。。。。几乎是一个学 JS 的人必会。

不过,这次我结合 animationend 事件写一个,带有渐隐效果的轮播。以前都是用 jQuery,今天换个思路。

HTML 代码如下:

<div class="picShow">
    <ul class="picUl" id="picUl">
        <li><a href="#"><img src="../images/pic1.jpg" alt=""></a></li>
        <li><a href="#"><img src="../images/pic2.jpg" alt=""></a></li>
        <li><a href="#"><img src="../images/pic3.jpg" alt=""></a></li>
        <li><a href="#"><img src="../images/pic4.jpg" alt=""></a></li>
        <li><a href="#"><img src="../images/pic5.jpg" alt=""></a></li>
    </ul>
    <div class="picDots" id="picDots"></div>
</div>
  • 轮播的控制点利用 DOM,根据图片的个数( li 的个数)动态生成;
  • 默认图片是隐藏的,display:none;
  • li 的显示和隐藏是这个案例的关键,因此,把标签的隐藏和显示分别封装成了 函数。其中,为了过渡隐藏动画,利用了 animationend 事件。当隐藏动画完毕后,让标签 display:none;

CSS代码如下:

*{
    margin: 0;
    padding: 0;
}
img{
    border:none;
}
ul,li,ol{
    list-style: none;
}
.picShow{
    position: relative;
    margin-left: auto;
    margin-right: auto;
}
.picShow,
.picUl>li,
.picUl>li>a{
    width: 600px;
    height: 399px;
    overflow: hidden;
}
.picUl>li>a{
    display: block;
}
.picUl>li{
    position: absolute;
    top:0;
    left:0;
    display: none;
}
.picUl>li.show{
    display: block;
}
.picDots {
    position: absolute;
    right:20px;
    bottom:20px;
}
.picDots span{
    display: inline-block;
    width: 16px;
    height: 16px;
    background: #fff;
    margin-left: 10px;
    cursor: pointer;
}
.picDots span.on{
    background: #f30;
}
@keyframes showAni {
    0%{
        opacity: 0;
    }
    100%{
        opacity: 1;
    }
}
@keyframes hideAni {
    0%{
        opacity: 1;
    }
    100%{
        opacity: 0;
    }
}

JavaScript 代码如下: 

let li = document.querySelectorAll("#picUl>li");
let dots = document.getElementById("picDots");
let span = [];
function  init(){
    for(let i=0; i<=li.length-1 ; i++ ){
        // 动态生成轮播的控制点
        let newSpan = document.createElement("span");
        dots.appendChild(newSpan);
        span.push(newSpan);
        if( i===0 ){
            newSpan.className = "on";
        }
        // 给每个 li 添加 animationend 事件
        li[i].addEventListener("animationend",function(event){
            if( event.animationName === "hideAni"){
                this.classList.remove("show");
            }
        });
    }
    showTag(li[0]);
}
// 显示某个标签
function showTag(tag){
    tag.classList.add("show");
    tag.style.animation = `showAni 0.5s both`;
}
// 隐藏某个标签
function hideTag(tag){
    tag.style.animation = `hideAni 0.5s both`;
}
init(); // 初始化函数
// 给 span 添加事件
for(let i=0 ; i<= span.length-1; i++){
    span[i].addEventListener("click",function(){
        this.classList.add("on");
        showTag(li[i]);
        // 其余的点去掉 on,其余的 li 隐藏。
        for(let j=0 ; j<=span.length-1 ; j++ ){
            if( j!==i){
                span[j].classList.remove("on");
                hideTag(li[j]);
            }
        }
    });
}

案例4:带退出动画的轮播

具体效果可以参考网游逆水寒的官网。

在人物轮播中,旧的内容动画退出后,才出现新的人物。

借用前面的思路,我也来做一个简单的带退出动画的轮播。

样式写的简陋,但是思路很重要。

HTML结构:

<div class="box">
    <ul class="picUl" id="picUl">
        <li>
            <img src="../images/1.jpg" alt="">
            <h1>图片1</h1>
        </li>
        <li>
            <img src="../images/2.jpg" alt="">
            <h1>图片2</h1>
        </li>
        <li>
            <img src="../images/3.jpg" alt="">
            <h1>图片3</h1>
        </li>
    </ul>
    <div class="dots" id="dots"></div>
</div>

CSS:要在CSS 里写出每个部分的进入、退出动画。

*{
    margin: 0;
    padding: 0;
}
ul,li,ol{
    list-style: none;
}
img{
    border:none;
}
.picUl img{
    width: 200px;
}
.box{
    background: #ff0;
    margin-left: auto;
    margin-right: auto;
    position: relative;
    overflow: hidden;
}
.box,
.picUl>li{
    width: 400px;
    height: 200px;
    overflow: hidden;
}
.picUl>li  img{
    position: absolute;
    left:0;
    top:30px;
}
.picUl>li  h1{
    position: absolute;
    right:0;
    top:30px;
}
.picUl>li{
    display: none;
}
.picUl .show{
    display: block;
}
@keyframes leftIn {
    0%{
        opacity: 0;
        transform: translateX(-100px);
    }
    100%{
        opacity: 1;
        transform: translateX(0);
    }
}
@keyframes leftOut {
    0%{
        opacity: 1;
        transform: translateX(0);
    }
    100%{
        opacity: 0;
        transform: translateX(-100px);
    }
}
@keyframes rightIn {
    0%{
        opacity: 0;
        transform: translateX(100px);
    }
    100%{
        opacity: 1;
        transform: translateX(0);
    }
}
@keyframes rightOut {
    0%{
        opacity: 1;
        transform: translateX(0);
    }
    100%{
        opacity: 0;
        transform: translateX(100px);
    }
}
.dots{
    position: absolute;
    left:0;
    right:0;
    bottom:10px;
    text-align: center;
}
.dots span{
    display: inline-block;
    width: 16px;
    height: 16px;
    background: #fff;
    margin-left: 5px;
    margin-right: 5px;
    cursor: pointer;
}
.dots span.on{
    background: #f00;
}

JavaScript:

let dots = document.getElementById("dots");
let li = document.querySelectorAll("#picUl>li");
let img = document.querySelectorAll("#picUl img");
let nowIndex = 0;
let nextIndex = 0 ;
let dotSpan = [];
function init(){
    for(let i=0 ; i<=li.length-1 ; i++){
        let newSpan = document.createElement("span");
        dots.appendChild(newSpan);
        dotSpan.push( newSpan );
        if( i === 0 ){
            newSpan.classList.add("on");
        }
    }
    showTag( li[0] );
}
function showTag(tag){
    tag.classList.add("show");
    tag.children[0].style.animation = "leftIn 0.3s both";
    tag.children[1].style.animation = "rightIn 0.3s both";
}
function hideTag(tag){
    tag.children[0].style.animation = "leftOut 0.3s both";
    tag.children[1].style.animation = "rightOut 0.3s both";
}
init();  // 初始化init

// 给图片添加动画事件。当图片动画结束后,让 li 隐藏
// 给控制点添加事件
for(let i=0 ; i <= li.length-1 ; i++ ){
    img[i].addEventListener("animationend",function(event){
       if( event.animationName === "leftOut" ){
           this.parentNode.classList.remove("show");
       }
    });
    dotSpan[i].addEventListener("click",function(){
        this.classList.add("on");
        for( let j=0 ; j <= li.length-1 ; j++ ){
            if( j !== i ){
                dotSpan[j].classList.remove("on");
                hideTag( li[j] )
            }
        }
        // 待退出后,再执行进入动画;
        // 不写 setTimeout ,直接 运行 showTag
        // 则是退出和进入同时进行
        setTimeout(function(){
            showTag( li[i] );
        },300);
    });
}

瞬间觉得轮播太有意思了~~

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值