资讯专栏INFORMATION COLUMN

前端每日实战 169# 视频演示如何制作“数略词”交互动画(内含2个视频)

roland_reed / 2030人阅读

摘要:本项目将制作一个交互动画效果,令其在单词原词和数略词之间切换。二扩展应用到多个单词数略词有很多,为了能够一次展示多个单词,我们将对现有的程序进行扩展。

效果预览

按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。

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

可交互视频

此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。

请用 chrome, safari, edge 打开观看。

视频1: https://scrimba.com/p/pEgDAM/cR4gpGsa
视频2: https://scrimba.com/p/pEgDAM/czNp3MUZ

源代码下载

每日前端实战系列的全部源代码请从 github 下载:

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

代码解读

大家是否见过 “i18n”、“a11y” 这样的英文单词?它们其实是一些单词的缩写,“i18n” 代表的是 “internationalization”(国际化),“a11y” 代表的是 “accessibility”(可访问性),因为包含的字母太多了,所以缩写时只保留头尾的字母,再把余下的字符个数写在中间,这种写法称为“Numeronym”,我把它翻译成“数略词”。据说最长的单词是 “pneumonoultramicroscopicsilicovolcanoconiosis”,由 45 个字母组成,意思是一种肺部疾病。

本项目将制作一个交互动画效果,令其在单词原词和“数略词”之间切换。整个项目分成二个步骤开发,第一步先实现一个固定单词的交互动画,第二步改写为能自动处理任意的单词,然后扩展应用到多个单词上。

一、一个固定单词的交互动画

dom 结构如下,最外侧的容器名为 .container,其中包含一个名为 .word

元素,它代表一个单词,它的子元素是 4 个

元素,分别代表单词的第1个字母、中间字符的个数(.middle.short)、中间的若干字符(.middle.long)、单词的最后1个字母。因为动画时将交替显示“中间字符的个数”和“中间的若干字符”,所以为它们设置了特殊类名,以便在随后的 css 代码中引用它们,当要同时选择它们时,就用它们共同的类名 middle,当要分别选择时,就指定它们各自的类名 shortlong

i

18

nternationalizatio

n

令容器居于页面正中:

body {
    margin: 0;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-image: linear-gradient(bisque, lightcyan);
}

让 4 个

标签包含的文字横向排列在容器中部:

.container {
    width: 100%;
}

.word {
    font-size: 35px;
    font-family: monospace;
    display: flex;
    justify-content: center;
}

把 2 个中间的

元素的文字上色,突出显示它们:

.middle {
    color: tomato;
}

接下来制作交互动画效果。

先把中间的若干字符隐藏起来,只显示中间字符的个数,在 html 代码中找到 .middle.long 元素,为它增加一个 hide 样式类:

在 css 中将 .middle.hide 元素的宽度设置为 0,并且不显示超出容器的部分:

.middle {
    overflow: hidden;
}

.middle.hide {
    width: 0;
}

令鼠标悬停在单词上时,鼠标指针变成一只手,提示用户此时可以点击:

.word:hover {
    cursor: pointer;
}

.word 元素增加鼠标点击事件,当单词被点击时,2 个中间元素分别切换 hide 类,交替显示两者中的一个元素,这些代码写在一个名为 initWordElement() 的方法中。在页面载入时将执行 init() 方法,再在其中调用 initWordElement() 方法。没有让 window.onload 直接执行 initWordElement() 方法,而是通过 init() 来调用,是因为在页面初始化阶段还会要做一些其他操作,后面还会逐渐充实 init() 方法:

window.onload = init

function init() {
    let el = document.querySelector(".word")
    initWordElement(el)
}

function initWordElement(el) {
    let middles = el.querySelectorAll(".middle")
    el.onclick = () => middles.forEach(m => m.classList.toggle("hide"))
}

现在,在页面上多次点击单词,能看到单词的中间部分不断切换了,不过这时还没有动画效果,接下来为切换增加缓动效果。

先为中间的 2 个元素设置宽度,这 2 个值是手工测量得到的,这不是最终的写法,后面我们会改成用脚本自动测量得到元素的宽度,不过因为现在我们要解决的是动画效果,所以先临时硬编码一下:

加缓动:

.middle {
    transition: 1s;
}

.middle.short {width: 42px;}
.middle.long {width: 378px;}

设置缓时长为 1 秒:

.middle {
    transition: 1s;
}

现在,点击单词时的切换效果,已经有了动画过程,接下来细化动画效果。

切换可以理解由 2 个动作组成:一个中间元素消失,另一个中间元素出现,通过增加缓动延时来实现这个效果:

.middle {
    transition: 1s;
    transition-delay: 1s;
}

.middle.hide {
    transition: 1s;
}

现在,当改变元素宽度时,是以元素的左侧为起点改变宽度的,不够漂亮,我们把它改成以中间为中点改变宽度,这样当元素变宽时,就向两侧延伸,当元素变窄时,就向中间收缩:

.middle {
    position: relative;
}

.middle span {
    position: absolute;
    transform: translateX(0);
    transition: 1s;
    transition-delay: 1s;
}

.middle.hide span {
    transform: translateX(-50%);
    transition: 1s;
}

接下来修改缓动时长,由 1s 缩短为 0.5s,也就是令动画速度加快一倍。为了能方便调试和维护,我们把时长的值定义为变量 --t

.word {
    --t: 0.5s;
}

.middle {
    transition: var(--t);
    transition-delay: var(--t);
}

.middle span {
    transition: var(--t);
    transition-delay: var(--t);
}

.middle.hide {
    transition: var(--t);
}

.middle.hide span {
    transition: var(--t);
}

至此,动画效果制作完成。

二、扩展应用到多个单词

“数略词”有很多,为了能够一次展示多个单词,我们将对现有的程序进行扩展。

先引入 lodash 库,我们将利用它提供的一个模板函数来处理 html 模板:

扩展 dom 结构,.container 容器中将包含不止一个 .word 元素,而是多个 .word 元素了。

创建一个 html 模板,它的内容是 .word 元素的代码,其中的第一个字母、中间字符个数、中间的若干字符、最后一个字母,这些内容在模板中分别用变量 firstmiddleLengthmiddlelast 表示:

而原 .container 元素中的内容都要删除掉,以便动态填充:

写一个名为 getWordObject() 的获取单词对象的函数,输入是一个单词,如“internationalization”,输出是一个对象,这个对象的属性与 html 模板中的变量相对应:

function getWordObject(w) {
    return {
        first: w.slice(0, 1),
        last: w.slice(-1),
        middle: w.slice(1, -1),
        middleLength: w.slice(1, -1).length,
    }
}

接下来写一个名为 createWordElement() 的方法,用于创建一个 .word 元素,在这个方法中使用了 lodash 的 _.template() 模板函数。该方法的输入是一个单词,将传递给 getWordObject() 函数:

function createWordElement(word) {
    const TEMPLATE = document.querySelector("#template").innerHTML

    let el = document.createElement("div")
    el.className = "word"
    el.innerHTML = _.template(TEMPLATE)(getWordObject(word))

    return el
}

在负责页面初始化的 init() 方法中调用 createWordElement() 方法,整个流程改为先创建一个元素,然后把该元素添加到 .container 容器中,再初始化这个元素:

function init() {
    let word = "internationalization"
    let el = createWordElement(word)
    document.querySelector(".container").appendChild(el)
    initWordElement(el)
}

现在,运行一下页面,虽然运行效果没有任何变化,但是 css 的属性、页面元素都已经变成动态生成的了。如果把 init() 方法中的 word 变量值改为其他单词,如 “accessibility”,页面中就会显示 “a11y”
了。

不过,在单词变为 “a11y” 之后,中间元素占据的宽度就不正确了,这是因为此前中间元素的宽度是硬编码的,需要把它们改为用脚本赋值。先删除掉 css 中的这 2 行代码:

/* .middle.short {width: 42px;}
.middle.long {width: 378px;} */

然后为 .middle 元素设置宽度属性,属性值是名为 --w 的变量:

.middle {
    width: var(--w);
}

然后在 initWordElement() 方法中增加一行,为变量 --w 赋值:

function initWordElement(el) {
    let middles = el.querySelectorAll(".middle")

    middles.forEach(m => 
        m.style.setProperty("--w", 
            window.getComputedStyle(m.querySelector("span")).width))

    el.onclick = () => middles.forEach(m => m.classList.toggle("hide"))
}

好了,现在不论把单词换成什么,都能合适地展现了,至此,单个单词的动态改造就完成了。

接下来请孙大圣拔下几根毫毛,帮我们把一个单词变成多个单词吧。

修改 init() 方法,删除掉 word 变量,定义一个名为 WORDS 的数组,遍历这个数组,为数组中的每个单词创建一个 .word 元素:

function init() {
    const WORDS = [
        "localization",
        "accessibility",
        "internationalization",
        "supercalifragilisticexpialidocious", 
        "pneumonoultramicroscopicsilicovolcanoconiosis"
    ]

    WORDS.forEach(word => {
        let el = createWordElement(word)
        document.querySelector(".container").appendChild(el)
        initWordElement(el)
    })
}

现在,页面上已经有 5 个单词了,点击那个 “p43s” 看看世界上最长的单词吧。

最后,因为

元素的外边距较大,把它调整得小一点,让纵向的几个单词排列得紧凑一点:

.word p {
    margin: 0.3em 0;
}

大功告成!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/114824.html

相关文章

  • 前端每日实战 169# 视频演示如何制作略词交互动画内含2视频

    摘要:本项目将制作一个交互动画效果,令其在单词原词和数略词之间切换。二扩展应用到多个单词数略词有很多,为了能够一次展示多个单词,我们将对现有的程序进行扩展。 showImg(https://segmentfault.com/img/bVbtPjm?w=400&h=401); 效果预览 按下右侧的点击预览按钮可以在当前页面预览,点击链接可以全屏预览。 https://codepen.io/co...

    sean 评论0 收藏0
  • 前端每日实战 169# 视频演示如何制作略词交互动画内含2视频

    摘要:本项目将制作一个交互动画效果,令其在单词原词和数略词之间切换。二扩展应用到多个单词数略词有很多,为了能够一次展示多个单词,我们将对现有的程序进行扩展。 showImg(https://segmentfault.com/img/bVbtPjm?w=400&h=401); 效果预览 按下右侧的点击预览按钮可以在当前页面预览,点击链接可以全屏预览。 https://codepen.io/co...

    tylin 评论0 收藏0
  • 前端每日实战 2018年10月至2019年6月项目汇总(共 20 项目)

    摘要:过往项目年月份项目汇总共个项目年月份项目汇总共个项目年月份项目汇总共个项目年月份项目汇总共个项目年月份项目汇总共个项目年月份项目汇总共个项目年月至年月发布的项目前端每日实战专栏每天分解一个前端项目,用视频记录编码过程,再配合详细的代码解读, 过往项目 2018 年 9 月份项目汇总(共 26 个项目) 2018 年 8 月份项目汇总(共 29 个项目) 2018 年 7 月份项目汇总(...

    muddyway 评论0 收藏0

发表评论

0条评论

roland_reed

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<