讓你網頁的Code語法 Hightlight起來
TL;DRWeb 端 Syntax Highlighting 三主流:Prism.js(輕量、CSS-based)、Highlight.js(老牌、語言多)、Shiki(2026 推薦)(VS Code 同款、build time 渲染、零 runtime cost)。配 rehype-pretty-code 是 Next.js / MDX 黃金組合。
教學 (一般React環境)
要在 React 中呈現帶有語法高亮的代碼塊,您可以使用第三方庫,例如,Prism.js 或 Highlight.js。這些庫可以自動對代碼進行語法高亮,並呈現具有顏色標記的代碼塊。
以 Prism.js 為例,您需要在 React 項目中安裝 Prism.js 庫:
npm install prismjs
npm i @types/prismjs --save-dev
然後,您需要匯入 Prism.js 並選擇您想要的語言(例如,JavaScript):
import React from 'react';
import Prism from 'prismjs';
import 'prismjs/components/prism-javascript';
function ExampleCodeBlock() {
return (
<pre>
<code className="language-javascript">
{`
// Example code block
function example() {
console.log("Hello, World!");
}
`}
</code>
</pre>
);
}
export default ExampleCodeBlock;
這段代碼定義了一個名為 **ExampleCodeBlock** 的 React 組件,該組件將返回一個預先格式化的代碼塊,其中包含示例代碼,並將其類名設置為 **language-javascript**。這將告訴 Prism.js 該代碼是 JavaScript 代碼,因此需要進行語法高亮。
您還需要匯入 Prism.js 的 CSS 樣式以使代碼塊顯示有顏色標記的語法高亮:
import 'prismjs/themes/prism.css';
請注意,您需要確保將 CSS 文件路徑正確引入您的 React 項目,並且它必須可以在 Web 浏览器中訪問到,以便使用
useEffect(() => {
Prism.highlightAll()
}, [])
Common CodeBlock 我寫好的
interface Props1 {
children: React.ReactNode
}
export const CodeBlockTS: React.FC<Props1> = ({ children }) => (
<pre>
<code className="language-typescript" >
{children}
</code>
</pre>
);
Next.js中如何使用
和前面的方法完全不同 (也許這個方法 前面也可以用這樣 但我還沒測試)
npm install prismjs
npm i @types/prismjs --save-dev
npm i react-syntax-highlighter
npm i @types/react-syntax-highlighter
然後打上這邊,之後就能夠使用了
import { Prism } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
<Prism language="javascript" style={vscDarkPlus}>
{`/* Your Code Here */`}
</Prism >
新增複製按鈕功能 (新版做法)
What is the easiest or recommended method to add a copy code button? · mdx-js · Discussion #1948Hi, I was wondering what is the easiest or recommended method to add a copy code button, like in the mdx docs page or like in the github markdown view. https://github.com/orgs/mdx-js/discussions/1948
先安裝clsx 為了讓css可以用複雜的邏輯
npm install clsx
接著創建一個複製的Commponent如下:記得搭配的是上面的Next.js中如何使用喔 (非Next.js中的第一版那個 最上面的我還沒測試)
import clsx from 'clsx'
import React from 'react'
interface ICopyToClipboard {
children: React.ReactNode
}
export const CopyToClipboard = ({ children }: ICopyToClipboard) => {
const textInput = React.useRef<HTMLDivElement>(null)
const [hovered, setHovered] = React.useState(false)
const [copied, setCopied] = React.useState(false)
const onEnter = () => {
setHovered(true)
}
const onExit = () => {
setHovered(false)
setCopied(false)
}
const onCopy = () => {
setCopied(true)
if (textInput.current !== null && textInput.current.textContent !== null)
navigator.clipboard.writeText(textInput.current.textContent)
setTimeout(() => {
setCopied(false)
}, 2000)
}
return (
<div
ref={textInput}
onMouseEnter={onEnter}
onMouseLeave={onExit}
className="relative code-block"
>
{hovered && (
<button
aria-label="Copy code"
type="button"
className={clsx(
'absolute right-2 top-2 w-8 h-8 p-1 rounded border-2 bg-gray-700 dark:bg-gray-800',
{
'focus:outline-none focus:border-green-400 border-green-400': copied,
'hover:border-gray-300': !copied,
}
)}
onClick={onCopy}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
stroke="currentColor"
fill="none"
className={copied ? 'text-green-400' : 'text-gray-300'}
>
{copied ? (
<>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
/>
</>
) : (
<>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
/>
</>
)}
</svg>
</button>
)}
{children}
</div>
)
}
我們只需要將程式碼如下 包起來就殼已了
<CopyToClipboard>
<Prism language="javascript" style={vscDarkPlus}>
{`service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
// 只允許已經通過身份驗證的用戶進行讀寫
allow read, write: if request.auth.uid != null;
}
}
}`}
</Prism>
</CopyToClipboard>
最後我們優化一下
我們直接把Prism元件放到CopyToCLipboard去,這樣使用就更方便。
import clsx from 'clsx'
import React from 'react'
import { Prism } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
interface ICopyToClipboard {
children: string
}
export const CopyToClipboard = ({ children }: ICopyToClipboard) => {
const textInput = React.useRef<HTMLDivElement>(null)
const [hovered, setHovered] = React.useState(false)
const [copied, setCopied] = React.useState(false)
const onEnter = () => {
setHovered(true)
}
const onExit = () => {
setHovered(false)
setCopied(false)
}
const onCopy = () => {
setCopied(true)
if (textInput.current !== null && textInput.current.textContent !== null)
navigator.clipboard.writeText(textInput.current.textContent)
setTimeout(() => {
setCopied(false)
}, 2000)
}
return (
<div
ref={textInput}
onMouseEnter={onEnter}
onMouseLeave={onExit}
className="relative code-block"
>
{hovered && (
<button
aria-label="Copy code"
type="button"
className={clsx(
'absolute right-2 top-2 w-8 h-8 p-1 rounded border-2 bg-gray-700 dark:bg-gray-800',
{
'focus:outline-none focus:border-green-400 border-green-400': copied,
'hover:border-gray-300': !copied,
}
)}
onClick={onCopy}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
stroke="currentColor"
fill="none"
className={copied ? 'text-green-400' : 'text-gray-300'}
>
{copied ? (
<>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
/>
</>
) : (
<>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
/>
</>
)}
</svg>
</button>
)}
<Prism language="jsx" style={vscDarkPlus}>
{children}
</Prism>
</div>
)
}
就只需要使用CopyToClipboard然後寫上code就完成了
<CopyToClipboard>
{`service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
// 只允許已經通過身份驗證的用戶進行讀寫
allow read, write: if request.auth.uid != null;
}
}
}`}
</CopyToClipboard>
新增複製按鈕功能 (舊版作法)
npm i react-copy-to-clipboard
npm i @types/react-copy-to-clipboard
之後就可以使用啦
import React from 'react';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { CopyToClipboard } from 'react-copy-to-clipboard';
<CopyToClipboard text={`your code`}>
<button>Copy</button>
</CopyToClipboard>