马黑黑 发表于 2025-7-27 23:23

千年之约(文本动画)

<style>
    #pa { margin: 20px auto; width: 100%; height: 460px; position: relative; }
    .text {
      margin: 10px;
      font: bold 60px 'Microsoft YaHei', sans-serif;
      color: #eee;
      text-shadow: 0 0 1px #000, 2px 2px 6px #333;
      display: inline-block;
    }
    .ani { animation: circle 2s linear; }
    @keyframes circle {
      to { transform: rotate(360deg); }
    }
</style>

<div id="pa"></div>

<script>
    const txtAr = '千年之约'.split('');
    let spans = [];
    txtAr.forEach( (t,k) => {
      const s = document.createElement('span');
      s.textContent = t;
      s.className = k === 0 ? 'text ani' : 'text';
      spans.push(s);
      s.onanimationend = () => {
            s.classList.remove('ani');
            spans[(k+1) % txtAr.length].classList.add('ani');
      };
      pa.appendChild(s);
    });
</script>

马黑黑 发表于 2025-7-27 23:23

参考代码

<style>
    #pa { margin: 20px auto; width: 100%; height: 460px; position: relative; }
    .text {
      margin: 10px;
      font: bold 60px 'Microsoft YaHei', sans-serif;
      color: #eee;
      text-shadow: 0 0 1px #000, 2px 2px 6px #333;
      display: inline-block;
    }
    .ani { animation: circle 2s linear; }
    @keyframes circle {
      to { transform: rotate(360deg); }
    }
</style>

<div id="pa"></div>

<script>
    const txtAr = '千年之约'.split('');
    let spans = [];
    txtAr.forEach( (t,k) => {
      const s = document.createElement('span');
      s.textContent = t;
      s.className = k === 0 ? 'text ani' : 'text';
      spans.push(s);
      s.onanimationend = () => {
            s.classList.remove('ani');
            spans[(k+1) % txtAr.length].classList.add('ani');
      };
      pa.appendChild(s);
    });
</script>

马黑黑 发表于 2025-7-27 23:32

用于帖子时,#pa 应改为别的名称、宽高另定、设为绝对定位,便于在帖子上安排位置。

动画可以换成别的方式。

动画工作原理:创建 span 标签时,第一个标签立即添加上.ani 类(24行代码),它运行 circle 动画;每一个 span 标签在运行完关键帧动画后,立马从 classList 列表中移除 ani 类,下一个则添加上 ani 类,这样N个 span 标签会轮次运行动画(26~29行代码)。

span 标签默认是行内标签,需要在CSS里给它添加一个 display: inline-block; 属性值,或者,将 span 标签设置为绝对定位(需要额外安排位置)。

亚伦影音工作室 发表于 2025-7-28 09:06

马黑黑 发表于 2025-7-27 23:32
用于帖子时,#pa 应改为别的名称、宽高另定、设为绝对定位,便于在帖子上安排位置。

动画可以换成别的方 ...

真漂亮,谢谢老师!

杨帆 发表于 2025-7-28 13:34

真美!谢谢马老师精彩分享{:4_190:}

红影 发表于 2025-7-28 19:02

这个真好,能自己判断,并依次逐字运行动画,还能从头循环。
这些都是JS功劳呢,当然,是黑黑设计的JS,黑黑的功劳更大{:4_199:}

红影 发表于 2025-7-28 19:08

马黑黑 发表于 2025-7-27 23:32
用于帖子时,#pa 应改为别的名称、宽高另定、设为绝对定位,便于在帖子上安排位置。

动画可以换成别的方 ...

来学习一下动画工作原理,原来是从列表中移除和添加 ani 类的过程。
谢谢黑黑的讲解,学习了{:4_187:}

马黑黑 发表于 2025-7-28 19:29

红影 发表于 2025-7-28 19:02
这个真好,能自己判断,并依次逐字运行动画,还能从头循环。
这些都是JS功劳呢,当然,是黑黑设计的JS,黑 ...

{:4_203:}

马黑黑 发表于 2025-7-28 19:30

红影 发表于 2025-7-28 19:08
来学习一下动画工作原理,原来是从列表中移除和添加 ani 类的过程。
谢谢黑黑的讲解,学习了

这是常用的关键帧动画接力实现方法

马黑黑 发表于 2025-7-28 19:30

杨帆 发表于 2025-7-28 13:34
真美!谢谢马老师精彩分享

{:4_191:}

马黑黑 发表于 2025-7-28 19:30

亚伦影音工作室 发表于 2025-7-28 09:06
真漂亮,谢谢老师!

{:4_190:}

红影 发表于 2025-7-28 22:28

马黑黑 发表于 2025-7-28 19:30
这是常用的关键帧动画接力实现方法

关键帧动画接力实现方法,这个方法很重要,应该学会呢{:4_204:}

红影 发表于 2025-7-28 22:32

马黑黑 发表于 2025-7-28 19:29


的确应该谢黑黑的,你咋这表情{:4_173:}

马黑黑 发表于 2025-7-28 22:35

红影 发表于 2025-7-28 22:28
关键帧动画接力实现方法,这个方法很重要,应该学会呢

其实就是监听 animationend 事件,即动画播放完毕。设置为永远循环即 infinite 的动画没有这个事件,因为它总播放不完,只有设置了具体次数或不设置次数的才有播放完结的时候。

onanimationend 就是监听动画播放完毕的写法之一,这是传统用法,现在兴用 addEventListener() 方法,它们功能一致,后者更被青睐是因为它可以使用更多的参数并可以解除监听。

马黑黑 发表于 2025-7-28 22:38

红影 发表于 2025-7-28 22:32
的确应该谢黑黑的,你咋这表情

谢来谢去谢个没完{:4_170:}

红影 发表于 2025-7-29 13:16

马黑黑 发表于 2025-7-28 22:35
其实就是监听 animationend 事件,即动画播放完毕。设置为永远循环即 infinite 的动画没有这个事件,因为 ...

嗯,监听有执行和移出操作,就实现这样的效果了。

红影 发表于 2025-7-29 13:16

马黑黑 发表于 2025-7-28 22:38
谢来谢去谢个没完

也是,那个听黑黑,不谢了,把谢意放心里{:4_173:}

马黑黑 发表于 2025-7-29 13:17

红影 发表于 2025-7-29 13:16
也是,那个听黑黑,不谢了,把谢意放心里

丢了也行,放心里是个累赘

马黑黑 发表于 2025-7-29 13:18

红影 发表于 2025-7-29 13:16
嗯,监听有执行和移出操作,就实现这样的效果了。

大概是酱紫

红影 发表于 2025-7-29 19:52

马黑黑 发表于 2025-7-29 13:17
丢了也行,放心里是个累赘

不累赘呢,心里地方大,塞点什么都不觉得多啊{:4_173:}
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 千年之约(文本动画)