软件教程 2025年08月6日
0 收藏 0 点赞 174 浏览 3236 个字
摘要 :

在使用AI问答大模型时,AI都是一个字一个字的输出,那么到底该如何实现代码类似“打字式”输出的效果呢?在之前负责自研产品介绍任务时,落地页有个需求:需要以代码形式展……

在使用AI问答大模型时,AI都是一个字一个字的输出,那么到底该如何实现代码类似打字式”输出的效果呢?在之前负责自研产品介绍任务时,落地页有个需求:需要以代码形式展示安装方法和核心概念,要让代码一行行、字符一个个地呈现出来,就像大模型实时作答那样。当时我做得比较仓促,后来在官网看到自己之前写的内容,就想着能不能优化得更好些。

这次展示选用的代码是一段Python示例(这是我从网上随机找的,主要用于演示,不涉及实际运行可行性)。代码如下:

class SimpleBook:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return f\"\'{self.title}\' by {self.author}\"

class MiniLibrary:
    def __init__(self):
        self.collection = []

    def add_book(self, book):
        self.collection.append(book)
        print(f\"Added: {book}\")

# 创建书籍和小型图书馆实例
book1 = SimpleBook(\"奇幻旅程\", \"王小小\")
my_library = MiniLibrary()

# 添加书籍到图书馆
my_library.add_book(book1)

# 打印特定书籍信息
print(my_library.collection[0])

起初,我考虑用<span>标签包裹每一行代码,还打算给变量和函数设置不同的行类样式,现在看来这个方法有点笨拙。后来发现highlight.js库能更便捷地实现代码展示功能。由于我使用的是React框架,所以直接下载了react-highlight,它已经将highlight.js作为依赖。通过npm i react-highlight -S完成安装后,就可以进行初步尝试了。而且,还能根据喜好选择代码风格,我选用了monokai风格。实现代码展示的代码如下:

import Highlight from \'react-highlight\';
import \'highlight.js/styles/monokai.css\'; 
import \'./index.scss\'; 

const pythonCodeExample = `
class SimpleBook:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return f\"\'{self.title}\' by {self.author}\"

class MiniLibrary:
    def __init__(self):
        self.collection = []

    def add_book(self, book):
        self.collection.append(book)
        print(f\"Added: {book}\")

# 创建书籍和小型图书馆实例
book1 = SimpleBook(\"奇幻旅程\", \"王小小\")
my_library = MiniLibrary()

# 添加书籍到图书馆
my_library.add_book(book1)

# 打印特定书籍信息
print(my_library.collection[0])
`;

export default function CodeShow() {

  return (
    <div className=\"code-stage\">
      <Highlight className=\'python-code\' language=\"python\">
        {pythonCodeExample}
      </Highlight>
    </div>
  );
}

实现代码展示后,下一步就是添加打字效果。我的思路是把pythonCodeExample作为原始数据,再创建一个响应式变量typedCode,利用定时器定时更新typedCode的值。具体代码如下:

export default function CodeShow() {
  const [typedCode, setTypedCode] = useState(\'\');
  const indexReference = useRef(0); 

  useEffect(() => {
    const intervalId = setInterval(() => {
      if (indexReference.current < pythonCodeExample.length) {
        setTypedCode((prevTypedCode) => prevTypedCode + pythonCodeExample[indexReference.current]);
        indexReference.current++;
      } else {
        clearInterval(intervalId);
      }
    }, 50); 

    return () => clearInterval(intervalId);
  }, []);

  return (
    <div className=\"code-stage\">
      <Highlight className=\'python-code\' language=\"python\">
        {typedCode}
      </Highlight>
    </div>
  );
}

虽然实现了打字效果,但仔细查看后发现代码风格丢失了。检查发现import \'highlight.js/styles/monokai.css\';文件是存在的,进一步检查元素才知道,原来是标签类名发生了变化,从原本的hljs-classhljs-functionhljs-title等类名变成了hljs-stringhljs-attibute等。这意味着Highlight组件没有正确解析切割后的代码,导致未能达到预期效果。经过一番搜索,找到了两种解决方案:

  • 第一种是在打字过程中,使用<pre>标签显示普通文本,打字完成后再用Highlight组件渲染高亮代码。不过这种方法存在弊端,<pre>标签展示效果不够美观,和最终期望的样式差异较大,后期调整起来比较麻烦;
  • 第二种方法是让Highlight组件重新渲染,通过设置key={typedCode.length},强制Highlight组件在每次typedCode更新时重新解析代码,以此实现动态高亮效果。

权衡之下,我选择了第二种方法,下面是完整代码:

export default function CodeShow() {
  const [typedCode, setTypedCode] = useState(\'\');
  const indexReference = useRef(0);

  useEffect(() => {
    const intervalId = setInterval(() => {
      if (indexReference.current < pythonCodeExample.length) {
        setTypedCode((prevTypedCode) => prevTypedCode + pythonCodeExample[indexReference.current]);
        indexReference.current++;
      } else {
        clearInterval(intervalId);
      }
    }, 50);

    return () => clearInterval(intervalId);
  }, []);

  return (
    <div className=\"code-stage\">
      <Highlight key={typedCode.length} className=\'python-code\' language=\"python\">
        {typedCode}
      </Highlight>
    </div>
  );
}

这种方法虽然牺牲了一些性能,但目前我还没想到更好的替代方案。要是大家有更优的实现方式,欢迎分享交流!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/6755.html

管理员

相关推荐
2025-08-06

文章目录 一、Promise基础回顾 二、Promise 与 axios 结合使用场景及方法 (一)直接返回 axios …

269
2025-08-06

文章目录 一、模块初始化时的内部机制 二、常见导出写法的差异分析 (一)写法一:module.exports…

107
2025-08-06

文章目录 一、ResizeObserver详解 (一)ResizeObserver是什么 (二)ResizeObserver的基本用法 …

683
2025-08-06

文章目录 一、前期准备工作 (一)下载相关文件 (二)安装必要工具 二、处理扣子空间生成的文件…

338
2025-08-06

文章目录 一、官方文档 二、自动解包的数据类型 ref对象:无需.value即可访问 reactive对象:保持…

371
2025-08-06

文章目录 一、Hooks的工作原理 二、在if语句中使用Hook会出什么岔子? 三、React官方的Hook使用规…

843
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号