CodeBlock
code-block展示多行代码,带语言标签和一键复制
用法
基础用法
传入多行代码(用 \n 换行),自动语法着色 + 右上角复制按钮。
<Lens zoom={1.8}>
<img src="/photo.jpg" />
</Lens>tsx
const code = `<Lens zoom={1.8}>
<img src="/photo.jpg" />
</Lens>`;
<CodeBlock code={code} />带语言标签
lang 在左上角显示语言标识,并影响着色规则。
tsx
import { Button } from "@hulianui/ui";
// 点击计数示例
export function Demo() {
const [n, setN] = useState(0);
return <Button onClick={() => setN(n + 1)}>点了 {n} 次</Button>;
}tsx
<CodeBlock code={code} lang="tsx" />Shell 命令
lang="bash" 按 Shell 规则着色命令名与 flag。
bash
# 安装并构建
pnpm add @hulianui/ui
pnpm --filter @hulianui/ui buildtsx
<CodeBlock code={shell} lang="bash" />Python
lang="python"(py / python3 同义)按 Python 词法着色:# 注释、三引号文档串、f-string、装饰器与内置名。
python
# 猜数字:把范围一半一半地砍
import functools
import random
SECRET = random.randint(1, 100)
@functools.cache
def guess(n: int) -> str:
"""比大小并给提示。
n 是玩家这一轮猜的数字。
"""
if not isinstance(n, int):
raise TypeError("只收整数")
if n == SECRET:
return f"猜中了,就是 {n}"
return "大了" if n > SECRET else "小了"
for i in range(0, 3):
print(guess(random.randint(1, 100)))tsx
<CodeBlock code={python} lang="python" />带行号
lineNumbers 显示行号,正文里就能指「第 12 行」。行号不可选中也不进复制内容;列宽按最大行号位数自适应;横向滚动时行号钉在左侧。片段从中间截取时用 lineNumbers={{ start: 120 }}。
python
# 猜数字:把范围一半一半地砍import functoolsimport randomSECRET = random.randint(1, 100)@functools.cachedef guess(n: int) -> str: """比大小并给提示。 n 是玩家这一轮猜的数字。 """ if not isinstance(n, int): raise TypeError("只收整数") if n == SECRET: return f"猜中了,就是 {n}" return "大了" if n > SECRET else "小了"for i in range(0, 3): print(guess(random.randint(1, 100)))<Lens zoom={1.8}> <img src="/photo.jpg" /></Lens>tsx
<CodeBlock code={python} lang="python" lineNumbers />
// 片段从第 120 行起算
<CodeBlock code={snippet} lang="python" lineNumbers={{ start: 120 }} />关闭着色 / 不可复制
highlight={false} 渲染纯文本;copyable={false} 去掉复制按钮。
import { Button } from "@hulianui/ui";
// 点击计数示例
export function Demo() {
const [n, setN] = useState(0);
return <Button onClick={() => setN(n + 1)}>点了 {n} 次</Button>;
}<Lens zoom={1.8}>
<img src="/photo.jpg" />
</Lens>tsx
<>
<CodeBlock code={code} highlight={false} />
<CodeBlock code={code} copyable={false} />
</>何时用
展示多行代码片段,自带语法着色、右上角语言标签与一键复制。单行命令/内联标识用 Snippet;只是一段内联 code 文字用 Code;展示前后差异用 CodeDiff。
导入
ts
import { CodeBlock, HighlightedCode, tokenizeCode, type CodeToken, type CodeTokenType } from "@hulianui/ui"Props
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
| code* | string | - | 代码文本,多行用 \n |
| lang | string | - | 右上角语言标签(如 "tsx"),同时决定着色规则走 JS 家族、Shell 还是 Python |
| copyable | boolean | true | 是否显示复制按钮 |
| highlight | boolean | true | 是否语法着色;关掉则纯文本 |
| lineNumbers | boolean | { start?: number } | false | 是否显示行号。{ start: 120 } 让片段从指定行号起算;列宽按最大行号的位数自适应 |
| className | string | - | 容器类名 |
着色支持的语言
| lang | 走哪套规则 |
|---|---|
js jsx ts tsx json | JS 家族 |
bash sh shell zsh console | Shell(命令名与 flag 分色) |
py python python3 | Python(# 注释、三引号文档串、f/r/b 前缀串、装饰器、内置名、0b/0o/0x/下划线/虚数字面量) |
| 其它 | 按 JS 家族近似处理 |
禁忌 / 坑
- `lang` 传到没有专门分支的语言,是「近似」不是「支持」。表里三类之外的语言一律按 JS 家族扫描:
yaml/toml/ini/dockerfile的#注释、SQL 的--注释都不会被当注释,注释正文会被当代码再扫一遍,里面的词还可能被着成 JS 关键字。这类语言要么接受它、要么先传highlight={false}保证不着错色,需要真正的着色档请来提 issue。 - 行号是装饰,不是内容。它
aria-hidden且不可选中:屏幕阅读器不念,用户框选整段代码复制时也不会混进1 2 3;复制按钮复制的始终是原始code。反过来说,别把「行号」当成可复制的数据来源。 - 行号列会一直钉在左侧(
sticky left-0+ 不透明底色)。长行横向滚动时行号不会滑走,代价是滚过去的代码会被行号列遮住一小条——这是刻意的取舍,长行看行号比看那一小条代码重要。 - 复制按钮读的是
navigator.clipboard,只在安全上下文(HTTPS / localhost)可用;HTTP 局域网页面里点了不会有反应。
相关
Playground
tsx
import { Button } from "@hulianui/ui";
// 点击计数示例
export function Demo() {
const [n, setN] = useState(0);
return <Button onClick={() => setN(n + 1)}>点了 {n} 次</Button>;
}<CodeBlock code={code} lang="tsx" />