马黑PHP整站系统

CSS关键帧动画文本效果:逐行出场

位置: 首页 > 前端三套件[ 发布时间: 2024.6.29  作者: 马黑  阅读: 209 ]

CSS关键帧动画文本效果:逐行出场

思路:用p标签装载每行文本,令其先待在div父容器右侧,再用CSS关键帧动画依次将p标签平移到默认时的位置,最后一句出场后间隔一定时间复位重来,整体动画循环往复并可暂停、继续。

实现

一、CSS和HTML

父元素是一个div标签,绝对定位,宽度需要设置一个合适的值;子元素是段落标签p,相对定位以便无需操心布局且transform能对之进行控制;关键帧动画非常简单,平移到 0 处,就是回到默认时的原位置。p标签暂不出现在HTML代码中,它们将由JS动态生成:

<style> #txtbox { position: absolute; left: 50px; top: 50px; width: 280px; min-height: 60px; padding: 10px 20px; box-sizing: border-box; overflow: hidden; } #txtbox p { margin: 8px 0; position: relative; font: normal 26px/30px sans-serif; color: navy; text-shadow: 1px 1px 1px gray; animation: 2s forwards; } @keyframes move { to { transform: translate(0); } } </style>   <div id="txtbox"></div>

基于上面的设计,@keyframes 属性制作的动画 transform: translate(0) 是不管用的,平移的尺寸按理应不能是 0,所以是不是 #txtbox p 选择器漏了一句?是的,漏了 transform: translate(280px); 属性设置,还有,animation 属性也不完整,漏了动画名称,这些,将由JS来完善和管理。

二、JS

首先需要几个全局变量:

var text = `西岳崚嶒竦处尊,诸峰罗立似儿孙。安得仙人九节杖,拄到玉女洗头盆。车箱入谷无归路,箭栝通天有一门。稍待秋风凉冷后,高寻白帝问真源。`; var paras = []; var reg = /[,。\n]/; var ww = txtbox.offsetWidth;

text 是待输出文本,反引号内的文本内容可以分行写;paras 是段落签数组,用来保存p标签元素;reg 是正则表达式,注意红色部分,中括号表示其里面的内容只要出现其中的一个便能匹配,这里设计了三个:① 汉语逗号,② 汉语句号,③换行符 \n,可以根据需要添加、删减或重新构造自己的正则;ww 是父div元素的宽度。

接着处理一下文本,将text按正则描述的规则拆分成若干单位、放入临时数组 ar 中并且,① 对 ar 数组过滤空文本数组元素,② 封装每一个数组元素内容为p标签、令其移动到父div元素外围右侧,③ 将封装好的p标签追加到父div元素,④ 将p标签一一存放到全局数组变量 paras 中。这个功能用一个立即执行函数完成:

(function () { var ar = text.split(reg).filter(item => item !==''); ar.forEach((p,k) => { var para = document.createElement('p'); para.innerHTML = p; para.style.cssText += `transform: translate(${ww}px);`; txtbox.appendChild(para); paras.push(para); }); })();

现在,paras 数组变量已经准备就绪,可以遍历它做一些实际性工作了:

paras[0].style.animationName = 'move'; paras.forEach((p,k) => { p.onanimationend = () => { paras[(k+1) % paras.length].style.animationName = 'move'; if(k === paras.length - 1) setTimeout( () => parasReset(), 10000); }; });

上面,我们先是给第一个p标签 paras[0] 指派关键帧动画名。接着,用 array.forEach() 方法遍历了数组 paras,批量定制了p元素的 onanimationend 事件(动画结束事件):当前 p 标签的该事件触发时,给下标为 (k+1) % paras.length 的p标签设置动画名称。使用遍历索引加1取数组长度的余数获得数组元素下标是个巧妙的方法:遍历具有迭代特性,每次的 k 变量指向当前数组元素,它的下一个数组元素自然是 k+1,但当循环到最后,k+1 的值会等于数组长度值(数组元素总量值)从而非法(数组元素下标从0开始起算),而 k+1 取数组长度的余数,在前面均等于 k+1 本身,而当 k+1 等于数组长度时会得到 0,也就是回到第一个数组元素即给第一个数组元素指定动画。然后,要使得动画循环运行,我们需要加入一个处理机制(代码第 6 行):最后一个p标签关键帧动画结束时,使用定时器 setTimeout 间隔预定时间后调用该处理机制的函数 parasReset(),函数长如下酱紫:

var parasReset = () => { paras.forEach(p => { p.style.animationName = ''; p.style.transform = 'translate(${ww}px)'; setTimeout( () => { paras[0].style.animationName = 'move'; }, 500); }); };

函数 parasReset() 遍历存储p标签的数组 paras,清空所有p标签的动画(必须,否则无法继续执行后面的同名动画)并将之统统移动到父div盒子的右侧外围,最后,再用一个 setTimeout 定时器在N毫秒之后给第一个p标签指定动画名称(这里的定时器必须使用,因为JS是同步运行机制,CSS动画名交替则要求,如果赋予的是同名动画,则不能取消之后立马重新赋予,需要一个时间差)。

至此,文本动画已经可以运行了,就差一个控制动画播放暂停的机制,我们用父div元素的窗体为载体,点击它时动画会在播放与暂停之间来回切换:

txtbox.onclick = () => { var state = window.getComputedStyle(paras[0]).getPropertyValue('animation-play-state'); paras.forEach(p => p.style.animationPlayState = state === 'running' ? 'paused' : 'running'); };

最后,将上述的代码整合一下:

<style> #txtbox { position: absolute; left: 50px; top: 50px; width: 280px; min-height: 60px; padding: 10px 20px; box-sizing: border-box; overflow: hidden; } #txtbox p { margin: 8px 0; position: relative; font: normal 26px/30px sans-serif; color: navy; text-shadow: 1px 1px 1px gray; animation: 2s forwards; } @keyframes move { to { transform: translate(0); } } </style> <div id="txtbox"></div>   <script> var text = `西岳崚嶒竦处尊,诸峰罗立似儿孙。安得仙人九节杖,拄到玉女洗头盆。车箱入谷无归路,箭栝通天有一门。稍待秋风凉冷后,高寻白帝问真源。`; var paras = []; var reg = /[,。\n]/; var ww = txtbox.offsetWidth; //自执行函数 :处理文本+p标签封装+追加+存储 (function () { var ar = text.split(reg).filter(item => item !==''); ar.forEach((p,k) => { var para = document.createElement('p'); para.innerHTML = p; para.style.cssText += `transform: translate(${ww}px);`; txtbox.appendChild(para); paras.push(para); }); })();   //p标签复位函数 var parasReset = () => { paras.forEach(p => { p.style.animationName = ''; p.style.transform = 'translate(${ww}px)'; setTimeout( () => { paras[0].style.animationName = 'move'; }, 500); }); };   //第一个p标签启用动画 paras[0].style.animationName = 'move';   //遍历p标签 :动态生成所有标签的动画结束事件 paras.forEach((p,k) => { p.onanimationend = () => { paras[(k+1) % paras.length].style.animationName = 'move'; if(k === paras.length - 1) setTimeout( () => parasReset(), 10000); }; });   //父div元素点击事件 :切换动画播放暂停 txtbox.onclick = () => { var state = window.getComputedStyle(paras[0]).getPropertyValue('animation-play-state'); paras.forEach(p => p.style.animationPlayState = state === 'running' ? 'paused' : 'running'); }; </script>

【提示】p标签在动态生成时使用 innerHTML 赋予其文本,这意味着 text 变量的赋值文本可以附带简单的HTML标签,诸如给特定关键词加粗体、前景色等修饰性标签。此外,可以通过CSS伪类选择器修饰对应的p标签,比如 :first-of-type、last-of-type 等。

前一篇: 实现原生lrc歌词同步之超级简化版
下一篇: 米字形圆环小播制作演示

发表评论:

       

评论列表 [1条]

#1 | 飞飞 于 2024-6-29 13:18 发布: 新的动画片。。文字按顺序排好并关键帧动画运行。点击可以暂停,结束可以循环。。

Copyright © 2023 All Right Reserved 马黑PHP文章管理整站系统v1.8
联系我们: gxblk@163.com