• 通过webkitAnimationEnd实现轮播动画


    通过webkitAnimationEnd实现轮播动画

    说到轮播动画,大家应该都知道swiper,我们也常常通过它来实现大部分轮播动画,但有时候项目比较简单,以及一些版本的问题,我们可以尝试一些其他简单的手段来实现轮播。比如webkitAnimationEnd

    一、webkitAnimationEnd是什么

    WebKit引擎的浏览器中,当CSS3的animation动画执行结束时,会触发webkitAnimationEnd事件。

    在以下示例中,当执行完一次animation动画,控制台就会触发webkitAnimationEnd事情,打印出“执行完一次animation”的字样。

    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>Documenttitle>
        <style>
    		* {
    			margin:0;
                padding: 0;
    		}
    		.container {
    			width: 200px;
    			white-space: nowrap;
    			overflow: hidden;
    			font-size: 20px;
    			color: #65b4ae;
                margin: 20px;
    		}
    		.container_words {
    			position: relative;
    			width: fit-content;
    			animation: move 4s linear;
                padding-left: 20px;
    		}
    		.container_words::after {
    			position: absolute; 
    			right: -100%;
    			content: attr(text);
    		}
    		@keyframes move {
    			0% {
    				transform: translateX(0);
    			}
    			100% {
    				transform: translateX(-100%);
    			}
    		}
    	style>
    head>
    <body>
        <div class="container">
            <p class="container_words" text="文字文字文字文字文字" id="word">
                文字文字文字文字文字
            p>
        div>
    body>
    <script>
        const word = document.querySelector('#word')
        const animateEvent = () => {
            console.log('执行完一次animation')
        }
        word.addEventListener('webkitAnimationEnd', animateEvent)
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    除此之外,还有webkitAnimationStart事件,它与webkitAnimationEnd相对应,一个是开始,一个是结束。
    以及webkitAnimationIteration事件,监听重复运动事件,每执行完一次animation触发一次。

    const animateEndEvent = () => {
        console.log('执行完一次animation')
    }
    const animateIterationEvent = () => {
        console.log('执行完一次循环animation')
    }
    // 设置animation: move 4s linear infinite; 无限循环的状态下,此事件触发不了
    word.addEventListener('webkitAnimationStart', animateStartEvent)
    // 设置animation: move 4s linear infinite; infinite便可监听到
    word.addEventListener('webkitAnimationIteration', animateIterationEvent )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    二、webkitAnimationEnd实现轮播

    那我们在实现轮播逻辑时,可以利用CSS3的动画属性结合其监听来实现。

    以下为一个简单示例:

    <template>
        <div class="task">
            <div
                :class="{ move }"
                @mouseover="pauseAni"
                @mouseout="playAni"
                ref="moveRow"
            >
                <div
                    class="task_item"
                    v-for="(item, index) in data"
                    :key="index"
                >{{ item }}</div>
            </div>
        </div>
    </template>
    
    <script>
    import { reactive, toRefs, onMounted, nextTick, onUnmounted } from "vue";
    export default {
        name: 'animateTest',
        setup() {
            const state = reactive({
                data: [1, 2, 3, 4, 5, 6],
                // 控制当前是否运动
                move: false,
                // 运动的元素DOM
                moveRow: null
            });
            let thread = null;
    
            const animateEvent = () => {
                // 基本逻辑,根据需求而定,此示例实现的上下一个一个的轮播
                const newList = JSON.parse(JSON.stringify(state.data));
                newList.push(newList.shift());
                state.data = newList;
                state.move = false;
            }
    
            const playAni = () => {
                // 判断一个数字,根据需求而定
                if (state.data.length > 2) {
                    thread = setInterval(() => {
                        state.move = true;
                    }, 5000);
                    // 监听webkitAnimationEnd事件
                    state.moveRow.addEventListener('webkitAnimationEnd', animateEvent);
                }
            };
    
            const clearTime = () => {
                if (thread) {
                    clearInterval(thread);
                    thread = null;
                }
            }
    
            const initAnimate = async () => {
                // 初始化动画
                clearTime();
                await nextTick();
                playAni();
            };
    
            const pauseAni = () => {
                clearTime();
            };
    
            onMounted(() => {
                initAnimate();
            });
    
            onUnmounted(() => {
            	// 清除监听
                state.moveRow && state.moveRow.removeEventListener('webkitAnimationEnd', animateEvent)
                clearTime();
            })
    
            return {
                ...toRefs(state),
                pauseAni,
                playAni,
            };
        },
    };
    </script>
    
    <style lang="scss" scoped>
    .task {
        position: relative;
        width: 488px;
        height: 284px;
        padding: 2px 25px 3px 18px;
        box-sizing: border-box;
        margin-top: 4px;
        background-color: rgb(213, 204, 204);
        overflow: hidden;
        
        .move {
            animation: slideAnimate 0.5s linear;
        }
    
        &_item {
            width: 100%;
            height: 142px;
            padding: 16px 0 17px 0;
            border-bottom: 1px dashed rgba(35, 93, 105, 1);
            color: #fff;
            text-align: center;
            line-height: 142px;
        }
    }
    @keyframes slideAnimate {
        from {
            transform: translateY(0);
        }
    
        to {
            transform: translateY(-142px);
        }
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    效果如下:
    在这里插入图片描述

    二、webkitAnimationIteration实现轮播

    那么根据上面的例子,我们也可以尝试使用webkitAnimationIteration改造,说不定可以达到更好的效果?

    • 第一步就需要让其循环执行。
      在这里插入图片描述

    但是我们发现,循环执行后,它会一直执行动画,而不能达到我们想要的:每执行一次动画前都停顿一段时间。而animation-delay只能设置设置动画在启动前的延迟间隔,它仅仅是在动画开启的第一次才会有暂停效果。

    但是我们可以另辟蹊径,如果我们的动画时间是0.5s,停顿时间是4.5s,那么我们可以采用设置运动时间为5s,但是让其前4.5s是不动的。例如:

    .move {
        animation: slideAnimate 5s linear infinite;
        /* animation: slideAnimate1 0.5s linear infinite; */
    }
    @keyframes slideAnimate {
        0% {
            transform: translateY(0);
        }
    
        90% {
            transform: translateY(0);
        }
    
        100% {
            transform: translateY(-142px);
        }
    }
    @keyframes slideAnimate1 {
        from {
            transform: translateY(0);
        }
    
        to {
            transform: translateY(-142px);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    但是这个方法需要去计算百分比,会有一点麻烦。

    • 那么接下来,我们直接监听webkitAnimationIteration事件,去实现相应的逻辑
    • 最后,鼠标移入暂停事件应该如何实现呢?

    我们可以利用animationanimation-play-state属性来控制。

    以下就是完整代码:

    <template>
        <div class="task">
            <div
                :class="['move', { pause }]"
                @mouseover="pauseAni"
                @mouseout="playAni"
                ref="moveRow"
            >
                <div
                    class="task_item"
                    v-for="(item, index) in data"
                    :key="index"
                >{{ item }}</div>
            </div>
        </div>
    </template>
    
    <script>
    import { reactive, toRefs, onMounted, nextTick, onUnmounted } from "vue";
    export default {
        name: 'animateTest',
        setup() {
            const state = reactive({
                data: [1, 2, 3, 4, 5, 6],
                // 运动的元素DOM
                moveRow: null,
                // 是否暂停动画
                pause: false,
            });
    
            const animateEvent = () => {
                // 基本逻辑
                const newList = JSON.parse(JSON.stringify(state.data));
                newList.push(newList.shift());
                state.data = newList;
            }
    
            const playAni = () => {
                // 判断一个数字,根据需求而定
                if (state.data.length > 2) {
                    state.pause = false;
                    // 监听webkitAnimationIteration事件
                    state.moveRow.addEventListener('webkitAnimationIteration', animateEvent);
                }
            };
    
            const initAnimate = async () => {
                await nextTick();
                playAni();
            };
    
            const pauseAni = () => {
                state.pause = true;
            };
    
            onMounted(() => {
                initAnimate();
                console.log(1)
            });
    
            onUnmounted(() => {
                state.moveRow && state.moveRow.removeEventListener('webkitAnimationIteration', animateEvent)
            })
    
            return {
                ...toRefs(state),
                pauseAni,
                playAni,
            };
        },
    };
    </script>
    
    <style lang="scss" scoped>
    .task {
        position: relative;
        width: 488px;
        height: 284px;
        padding: 2px 25px 3px 18px;
        box-sizing: border-box;
        margin-top: 4px;
        background-color: rgb(213, 204, 204);
        overflow: hidden;
        .move {
            animation: slideAnimate 5s linear infinite running;
    		/* 通过添加class来暂停动画 */
            &.pause {
                animation-play-state: paused;
            }
        }
    
        &_item {
            width: 100%;
            height: 142px;
            padding: 16px 0 17px 0;
            border-bottom: 1px dashed rgba(35, 93, 105, 1);
            color: #fff;
            text-align: center;
            line-height: 142px;
        }
    }
    @keyframes slideAnimate {
        0% {
            transform: translateY(0);
        }
    
        90% {
            transform: translateY(0);
        }
    
        100% {
            transform: translateY(-142px);
        }
    }
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
  • 相关阅读:
    软考复习(二):操作系统
    入坑计算机视觉必备的图像基础
    C语言-流程控制
    Spring和SpringBoot学习
    【元宇宙】5个视角,重新看待区块链和元宇宙
    python手柄pygame joystick文档
    node(三)express框架
    SpringBoot整合Shiro环境搭建与配置拦截器
    leetcode
    在微信小程序上做一个「博客园年度总结」:解决前端获取接口数据太慢的一种思路
  • 原文地址:https://blog.csdn.net/qq_40864647/article/details/126246689