马黑黑 发表于 2023-5-22 07:57

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 07:58

本帖最后由 马黑黑 于 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:18

本帖最后由 马黑黑 于 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() 函数,令程序进入工作状态。

焱鑫磊 发表于 2023-5-22 09:09

黑黑老师厉害了。{:4_187:}{:4_187:}{:4_187:}

亦是金 发表于 2023-5-22 10:40

谢谢老师教程!收藏学习备用!{:4_190:}

醉美水芙蓉 发表于 2023-5-22 11:44

马黑黑 发表于 2023-5-22 11:46

焱鑫磊 发表于 2023-5-22 09:09
黑黑老师厉害了。

果酱果酱

马黑黑 发表于 2023-5-22 11:47

亦是金 发表于 2023-5-22 10:40
谢谢老师教程!收藏学习备用!

还有一个可以控制的,马上发出

马黑黑 发表于 2023-5-22 11:47

醉美水芙蓉 发表于 2023-5-22 11:44
欣赏老师佳作!

中午好

南无月 发表于 2023-5-22 12:35

第一版实现方式不同,两版可对比学习。老师好细心

马黑黑 发表于 2023-5-22 12:54

南无月 发表于 2023-5-22 12:35
第一版实现方式不同,两版可对比学习。老师好细心

纯JS做的,有很多种实现方式,这里提供的两种,我个人觉得第二种比较好

红影 发表于 2023-5-22 17:02

这个好,换行更方便,而且时间掌握上完全和字数对应了。给黑黑点赞{:4_199:}

梦缘 发表于 2023-5-22 17:03

感谢老师的分享,欣赏点赞!{:4_178:}

红影 发表于 2023-5-22 17:05

去试了一下,空格也认的呢{:4_173:}

南无月 发表于 2023-5-22 17:56

马黑黑 发表于 2023-5-22 12:54
纯JS做的,有很多种实现方式,这里提供的两种,我个人觉得第二种比较好

我尽量努力看懂为啥第二种比较好{:4_170:}

马黑黑 发表于 2023-5-22 18:05

南无月 发表于 2023-5-22 17:56
我尽量努力看懂为啥第二种比较好

一个是观感,二个是可控性,三个是使用元素的多寡

南无月 发表于 2023-5-22 18:14

马黑黑 发表于 2023-5-22 18:05
一个是观感,二个是可控性,三个是使用元素的多寡

这么说的话就明白了,可控和代码少是可见的优势。观感没感觉,看上去差不多。。

马黑黑 发表于 2023-5-22 18:16

红影 发表于 2023-5-22 17:02
这个好,换行更方便,而且时间掌握上完全和字数对应了。给黑黑点赞

这个可以玩玩,但我总是不是太满意,主要在控制方面,需要的编程开销比较大

马黑黑 发表于 2023-5-22 18:17

红影 发表于 2023-5-22 17:05
去试了一下,空格也认的呢

它不会忽略空格,我编写代码的时候注意到了这一点,虽然我对此什么也没做{:4_170:}

马黑黑 发表于 2023-5-22 18:20

南无月 发表于 2023-5-22 18:14
这么说的话就明白了,可控和代码少是可见的优势。观感没感觉,看上去差不多。。

还是有差别的
页: [1] 2 3 4 5 6 7
查看完整版本: JS+CSS实现逐行逐字输出诗词方法之一