让代码像是打字一样显示在页面上

之前有一个介绍自研产品的任务,落地页需要用代码的形式展示一下安装方法,核心的几个概念,需求就是这样,让代码一行一行展示出来,字符一个个蹦出来,就好像大模型用代码作答一样。 之前没有考虑好,写的很匆促,今天在官网上又看到自己写的那个玩意,想想是不是可以写的再稍微好点。😆

我要做的是展示下面的代码(PS我网上随便找的一点Python代码,可行性与否不用在意,演示数据而已)

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;

tsx 复制代码
import Highlight from 'react-highlight';
import 'highlight.js/styles/monokai.css'; // 代码风格
import './index.scss'; // 滚动条,文字大小,居中显示等

const pyCode = `
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 CodeTyping() {

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

做好了展示,接下来做一下打字效果,我的想法是pyCode作为源数据,再用一个变量typedCode作为响应式数据,定时器定时更新下typedCode。

tsx 复制代码
export default function CodeTyping() {
  const [typedCode, setTypedCode] = useState('');
  const indexRef = useRef(0); // 使用 useRef 来保存当前索引

  useEffect(() => {
    const intervalId = setInterval(() => {
      if (indexRef.current < pyCode.length) {
        setTypedCode((prevTypedCode) => prevTypedCode + pyCode[indexRef.current]);
        indexRef.current++;
      } else {
        clearInterval(intervalId);
      }
    }, 50); // 调整间隔时间以改变打字速度

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

  return (
    <div className="code-stage">
      {/* 使用 Highlight 组件包裹你的代码,并设置语言属性 */}
      <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 更新时重新渲染,这样可以确保 Highlight 组件每次都重新解析代码,从而实现动态高亮。

我这里使用第二种方法,下面是完整代码:

tsx 复制代码
export default function CodeTyping() {
  const [typedCode, setTypedCode] = useState('');
  const indexRef = useRef(0);

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

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

  return (
    <div className="code-stage">
      {/* 使用 key 强制重新渲染 Highlight 组件 */}
      <Highlight key={typedCode.length} className='python-code' language="python">
        {typedCode}
      </Highlight>
    </div>
  );
}

这里是稍微牺牲了一点性能的,不过我没有想出更好的办法,各位有更好的实现,欢迎前来指导😁

相关推荐
Y42583 小时前
本地多语言切换具体操作代码
前端·javascript·vue.js
速易达网络6 小时前
Bootstrap 5 响应式网站首页模板
前端·bootstrap·html
etsuyou6 小时前
js前端this指向规则
开发语言·前端·javascript
lichong9516 小时前
Android studio 修改包名
android·java·前端·ide·android studio·大前端·大前端++
cai_huaer6 小时前
BugKu Web渗透之 cookiesWEB
前端·web安全
lichong9516 小时前
Git 检出到HEAD 再修改提交commit 会消失解决方案
java·前端·git·python·github·大前端·大前端++
友友马6 小时前
『 QT 』QT控件属性全解析 (一)
开发语言·前端·qt
不想上班只想要钱7 小时前
vue3+vite创建的项目,运行后没有 Network地址
前端·javascript·vue.js
流***陌7 小时前
手办盲盒抽赏小程序前端功能设计:兼顾收藏需求与抽赏乐趣
前端·小程序
岁月宁静7 小时前
在富文本编辑器中封装实用的 AI 写作助手功能
前端·vue.js·人工智能