JS+CSS实现逐行逐字输出诗词方法之一
<style>#mydiv {
width: 600px;
height: 400px;
border: 1px solid gray;
position: relative;
margin: 20px auto;
}
.zi {
position: absolute;
width: 50px;
height: 50px;
text-align: center;
font: bold 2em / 50px sans-serif;
text-shadow: 1px 1px 2px #000;
opacity: 0;
transition: 0.1s;
animation: output var(--tt) var(--delay) forwards;
}
@keyframes output {
0% { opacity: 0; }
95% { opacity: 0; }
100% { opacity: 1; }
}
</style>
<div id="mydiv"></div>
<script>
let sstr = `白居易·忆江南\n\n江南好,\n风景旧曾谙。\n日出江花红胜火,\n春来江水绿如蓝。\n能不忆江南?`;
let tt = 20, timer = null, mFlag = true;
let output = (ele,str) => {
ele.innerText = '';
let lines = str.split('\n'), ziNum = 0, delay = 0.2;
for(j = 0; j < lines.length; j ++) {
let ar = lines.split('');
for(k = 0; k < ar.length; k ++) {
ziNum ++;
let zi = document.createElement('span');
zi.className = 'zi';
zi.innerText = ar;
zi.style.cssText += `
left: ${k*40}px;
top: ${j* 40}px;
color: #${Math.random().toString(16).substr(-6)};
--tt: ${ziNum * delay}s;
--delay: ${ziNum * delay - delay}s;
`;
ele.appendChild(zi);
}
}
tt = ziNum * delay * 2000 + 2000;
};
let update = () => {
output(mydiv,sstr);
setTimeout(() => { update(); }, tt);
};
setTimeout(update,100);
</script>
本帖最后由 马黑黑 于 2023-5-22 08:18 编辑
代码
<style>
#mydiv {
width: 600px;
height: 400px;
border: 1px solid gray;
position: relative;
margin: 20px auto;
}
.zi {
position: absolute;
width: 50px;
height: 50px;
text-align: center;
font: bold 2em / 50px sans-serif;
text-shadow: 1px 1px 2px #000;
opacity: 0;
transition: 0.1s;
animation: output var(--tt) var(--delay) forwards;
}
@keyframes output {
0% { opacity: 0; }
95% { opacity: 0; }
100% { opacity: 1; }
}
</style>
<div id="mydiv"></div>
<script>
let sstr = `白居易·忆江南\n\n江南好,\n风景旧曾谙。\n日出江花红胜火,\n春来江水绿如蓝。\n能不忆江南?`;
let tt = 20;
let output = (ele,str) => {
ele.innerText = '';
let lines = str.split('\n'), ziNum = 0, delay = 0.2;
for(j = 0; j < lines.length; j ++) {
let ar = lines.split('');
for(k = 0; k < ar.length; k ++) {
ziNum ++;
let zi = document.createElement('span');
zi.className = 'zi';
zi.innerText = ar;
zi.style.cssText += `
left: ${k*40}px;
top: ${j* 40}px;
color: #${Math.random().toString(16).substr(-6)};
--tt: ${ziNum * delay}s;
--delay: ${ziNum * delay - delay}s;
`;
ele.appendChild(zi);
}
}
tt = ziNum * delay * 2000 + 2000;
};
let update = () => {
output(mydiv,sstr);
setTimeout(() => { update(); }, tt);
};
setTimeout(update,100);
</script>
本帖最后由 马黑黑 于 2023-5-22 08:22 编辑
说明:
一、思路
与前几天演示的css-doodle排版相关的文章一样,使用元素的 opacity 属性令文本从完全透明到不透明的方式逐一呈现出来。
二、CSS和HTML部分
(一)需要一个父窗体作为文字输出场景(#mydiv 选择器);
(二)文字个体(含标点)需要一个span元素装载(.zi 选择器);
(三)需要一个关键帧动画(@keyframes 设定的 output)。调用关键帧动画的 animation 属性内设两个CSS变量:--tt 是单字运行关键帧动画总时长,--delay 是延时执行动画的时间。
三、JS部分
(一)变量 sstr 是字符串变量,是要输出的诗词,规范是断行使用 \n 符号;
(二)变量 tt 是定时器运行周期时间(秒),预设的值随意,后面会根据字数重新计算赋值;
(三)函数 output(ele,str) 用于清除、加载文本,其思路是,每次执行它,先清空父窗体所有内容,然后设置、装载文本,在设置文本时,给每一个 span 标签定义好 ① 位置 ② 随机文本颜色 ③ 两个CSS变量值,最后计算出 JS变量 tt 值。
(四)函数 update() 运行(三)的函数,内置定时器 setTimeout 令其每隔 tt 毫秒循环执行 output(ele,str ) 函数,注意函数参数的代入值。
(四)其他
第60行启动一次 update() 函数,令程序进入工作状态。
黑黑老师厉害了。{:4_187:}{:4_187:}{:4_187:} 谢谢老师教程!收藏学习备用!{:4_190:} 焱鑫磊 发表于 2023-5-22 09:09
黑黑老师厉害了。
果酱果酱 亦是金 发表于 2023-5-22 10:40
谢谢老师教程!收藏学习备用!
还有一个可以控制的,马上发出 醉美水芙蓉 发表于 2023-5-22 11:44
欣赏老师佳作!
中午好 第一版实现方式不同,两版可对比学习。老师好细心 南无月 发表于 2023-5-22 12:35
第一版实现方式不同,两版可对比学习。老师好细心
纯JS做的,有很多种实现方式,这里提供的两种,我个人觉得第二种比较好
这个好,换行更方便,而且时间掌握上完全和字数对应了。给黑黑点赞{:4_199:} 感谢老师的分享,欣赏点赞!{:4_178:} 去试了一下,空格也认的呢{:4_173:} 马黑黑 发表于 2023-5-22 12:54
纯JS做的,有很多种实现方式,这里提供的两种,我个人觉得第二种比较好
我尽量努力看懂为啥第二种比较好{:4_170:} 南无月 发表于 2023-5-22 17:56
我尽量努力看懂为啥第二种比较好
一个是观感,二个是可控性,三个是使用元素的多寡 马黑黑 发表于 2023-5-22 18:05
一个是观感,二个是可控性,三个是使用元素的多寡
这么说的话就明白了,可控和代码少是可见的优势。观感没感觉,看上去差不多。。 红影 发表于 2023-5-22 17:02
这个好,换行更方便,而且时间掌握上完全和字数对应了。给黑黑点赞
这个可以玩玩,但我总是不是太满意,主要在控制方面,需要的编程开销比较大 红影 发表于 2023-5-22 17:05
去试了一下,空格也认的呢
它不会忽略空格,我编写代码的时候注意到了这一点,虽然我对此什么也没做{:4_170:} 南无月 发表于 2023-5-22 18:14
这么说的话就明白了,可控和代码少是可见的优势。观感没感觉,看上去差不多。。
还是有差别的