前端逐日实战 168# 视频演示怎样应用 Web Animation API 制造一个切换英语单词的交互动画

《前端逐日实战 168# 视频演示怎样应用 Web Animation API 制造一个切换英语单词的交互动画》

效果预览

按下右边的“点击预览”按钮能够在当前页面预览,点击链接能够全屏预览。

https://codepen.io/comehope/pen/byabeG

可交互视频

此视频是能够交互的,你能够随时停息视频,编辑视频中的代码。

请用 chrome, safari, edge 翻开寓目。

https://scrimba.com/p/pEgDAM/cevPbkfB

(由于 scrimba 不支持 web animation api,所以动画效果在视频播放历程当中看不到,不过你能够随时停息视频,手工革新预览窗口检察动画效果)

源代码下载

逐日前端实战系列的悉数源代码请从 github 下载:

https://github.com/comehope/front-end-daily-challenges

代码解读

本作品用于展现多少包括字母组合 OO 的单词,每点击一下,OO 就眨眨眼,同时替换一个单词。

团体开辟历程分红 4 步,第 1 步用 CSS 完成页面的静态规划,背面 3 步用 JS 完成动画和营业逻辑。第 2 步完成单词中心字母 OO 的眨眼效果,第 3 步完成随机取单词的逻辑,第 4 步完成字符的切换动画。

眨眼动画和字符切换动画都是用 Web Animation API 完成的。虽然用 JS 写动画比用 CSS 要贫苦一些,但 API 供应了一些事宜 handler,在字符切换动画中就是应用事宜机制来准确掌握动画和在动画历程当中到场营业逻辑的。

下面最先编码。

一、静态规划:dom,css

dom 构造很简朴,一个名为 .word<p> 元素中包括了 4 个 <span> 子元素,每个子元素包容一个字符:

<p class="word">
    <span>b</span>
    <span>o</span>
    <span>o</span>
    <span>k</span>
</p>

令页面中的元素居中,设置页面背景色为青蓝色:

body {
    margin: 0;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: steelblue;
}

设置单词的款式,夏布色,大字号,大写:

.word {
    font-size: 100px;
    color: linen;
    font-family: monospace;
    font-weight: bold;
    display: flex;
    text-transform: uppercase;
    cursor: pointer;
    user-select: none;
}

让单词两头的 2 个字符变成粉色:

.word span:first-child,
.word span:last-child {
    color: pink;
}

用径向渐变给单词中心的 OO 加上眸子:

.word span:not(:first-child):not(:last-child) {
    background-image: radial-gradient(
        circle at center,
        linen 0.05em,
        transparent 0.05em
    );
}

至此,静态规划完成。

二、眨眼动画

.word 元素建立一个单击事宜函数,每当点击发作时,就先让中心的 OO 眨眼,然后取得下一个要显现的单词,再把当前的单词换成新的单词:

document.querySelector('.word').onclick = function() {
    //第1步:眨眼动画
    //第2步:取得下一个单词
    //第3步:字符切换动画
}

先来完成第1步-眨眼动画。在此之前相识一下 Web Animation API 的语法,下面是一个简朴的示例:

let keyframes = [
    {transform: 'scaleY(1)'},
    {transform: 'scaleY(0.1)'},
]
let options = {
    duration: 200,
    iterations: 2,
}
element.animate(keyframes, options)

animate() 要领吸收 2 个参数,第 1 个参数是一个数组,用于定义关键帧;第 2 个参数是一个对象,用于定义动画属性,它们离别对应着 CSS 中的 @keyframes 语句和 animation 属性。上面的 JS 代码等价于以下 CSS 代码:

@keyframes anim {
    from {
        transform: scaleY(1);
    }

    to {
        transform: scaleY(0);
    }
}

.element {
    animation-name: anim;
    animation-duration: 200ms;
    animation-iteration-count: 2;
}

好了,我们来正式写眨眼动画:

function blinkEyes() {
    let eyes = document.querySelectorAll('.word span:not(:first-child):not(:last-child)')
    let keyframes = [
        {transform: 'scaleY(1)', offset: 0},
        {transform: 'scaleY(0.1)', offset: 0.25},
        {transform: 'scaleY(1)', offset: 0.5},
        {transform: 'scaleY(1)', offset: 1},
    ]
    let options = {
        duration: 200,
        iterations: 2,
    }
    eyes.forEach(eye => eye.animate(keyframes, options))
}

上面代码中的 offset@keyframes 中为每一帧指定的百分比值。这段动画的意义是每次动画眨眼 2 次,每次眨眼用时 200ms,这 200ms 的前 50% 时候(即前 100ms)做眨眼行动,后 50% 时候守候,如许设想的目标是在 2 次眨眼之间插进去 100ms 的距离。

然后,在点击事宜里挪用上面的要领:

document.querySelector('.word').onclick = function() {
    //第1步:眨眼动画
    blinkEyes()

    //第2步:取得下一个单词
    //第3步:字符切换动画
}

至此,当用鼠标点击笔墨时,OO 就会眨动。

三、取得下一个单词

接下来写一点营业逻辑,用于随机掏出一个单词。

引入 lodash 库:

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

定义一个名为 Word 的类:

function Word() {
    const WORDS = ['book', 'boot', 'cook', 'cool', 'door', 'food', 'fool', 'foot', 'good', 'look', 'loop', 'moon', 'noon', 'pool', 'poor', 'room', 'roof','root', 'soon', 'tool', 'wood', 'zoom',]
    let current = 'book'
    this.getNext = () => {return current = _(WORDS).without(current).sample()}
}

Word 类有一个名为 getNext() 的要领,用于从预设的数组中随机掏出一个单词,能够用下面的代码测试一下效果,会输出相似 food 如许的单词:

let word = new Word()
console.log(word.getNext())

由于接下来的动画只触及单词摆布两侧的字母,所以在 getNext() 要领中再把两头的字符拆出来,返回一个对象:

function Word() {
    const WORDS = ['book', 'boot', 'cook', 'cool', 'door', 'food', 'fool', 'foot', 'good', 'look', 'loop', 'moon', 'noon', 'pool', 'poor', 'room', 'roof','root', 'soon', 'tool', 'wood', 'zoom',]
    let current = 'book'
    this.getNext = () => {
        current = _(WORDS).without(current).sample()
        return {
            first: current.slice(0, 1),
            last: current.slice(-1)
        }
    }
}

再测试一下效果,输出效果会变成相似 {first: "f", last: "d"} 的对象。

在点击事宜中挪用上面的函数,把效果存入一个名为 chars 的变量中:

let word = new Word()

document.querySelector('.word').onclick = function() {
    //step 1: eyes blink animation
    blinkEyes()

    //第2步:取得下一个单词
    let chars = word.getNext()

    //第3步:字符切换动画
}

四、字符切换动画

该制造字符切换动画了。

函数的声明以下,函数名为 switchChar,它吸收 2 个参数,第 1 个参数示意对哪一个字符实行动画,值为 firstlast,第 2 个参数是将被替换成的新字符:

function switchChar(which, char) {}

如许来挪用:

switchChar('first', 'f')

先完成替换逻辑,不包括动画效果:

function switchChar(which, char) {
    let letter = {
        first: {
            dom: document.querySelector('.word span:first-child'),
        },
        last: {
            dom: document.querySelector('.word span:last-child'),
        }
    }[which]

    letter.dom.textContent = char
}

在点击事宜中挪用 switchChar 函数:

document.querySelector('.word').onclick = function() {
    //step 1: eyes blink animation
    blinkEyes()

    //第2步:取得下一个单词
    let chars = word.getNext()

    //第3步:字符切换动画
    Object.keys(chars).forEach(key => switchChar(key, chars[key]))
}

如今运转顺序的话,在每次点击以后,单词两侧的字符都邑更新。

接下来写动画效果,要领和写眨眼动画相似。这里有两点要申明,一是由于有 firstlast 2 个字符、又有入场、进场 2 个动画,所以实际上一共完成了 4 个动画效果;二是动画的流程是先让旧字符进场,再让新字符入场,而替换字符的操纵安排在这 2 个动画中心,这是用动画 API 的 onfinish 事宜完成的:

function switchChar(which, char) {
    let letter = {
        first: {
            dom: document.querySelector('.word span:first-child'),
            to: '-0.5em',
            from: '0.8em',
        },
        last: {
            dom: document.querySelector('.word span:last-child'),
            to: '0.5em',
            from: '-0.8em',
        }
    }[which]

    let keyframes = {
        out: [
            {transform: `translateX(0)`, filter: 'opacity(1)'},
            {transform: `translateX(${letter.to})`, filter: 'opacity(0)'},
        ],
        in: [
            {transform: `translateX(${letter.from})`, filter: 'opacity(0)'},
            {transform: `translateX(0)`, filter: 'opacity(1)'},
        ]
    }

    let options = {
        duration: 500,
        fill: 'forwards',
        easing: 'cubic-bezier(0.5, 1.5, 0.5, 1.5)'
    }

    letter.dom
        .animate(keyframes.out, options)
        .onfinish = function() {
            letter.dom.animate(keyframes.in, options)
            letter.dom.textContent = char
        }
}

至此,悉数编码完成。解读 JS 代码和解读 CSS 代码不一样,由于不是每一行代码都有视觉效果,很难用言语形貌。假如你有不理解的处所,一定是我没有讲清楚,那末请你多看几遍视频,细致体味。

在前端逐日实战的第 162 号作品中也曾使用过 Web Animation API,但谁人作品的营业逻辑比这个要庞杂,你在理解了这个作品以后若还想再应战一下,能够再去参考它。

功德圆满!

    原文作者:comehope
    原文地址: https://segmentfault.com/a/1190000019274437
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞