Skip to content

圍欄代碼塊

圍欄代碼塊是 Markdown 擴展語法的重要功能,提供了比基本代碼塊更強大的代碼展示能力,支持語法高亮、行號、文件名等高級特性。

基本圍欄代碼塊

三個反引號

使用三個反引號 ``` 創建代碼塊:

markdown
```
function hello() {
    console.log("Hello, World!");
}
```

渲染效果

function hello() {
    console.log("Hello, World!");
}

三個波浪號

也可以使用三個波浪號 ~~~ 創建代碼塊:

markdown
~~~
function hello() {
    console.log("Hello, World!");
}
~~~

渲染效果

function hello() {
    console.log("Hello, World!");
}

語法高亮

指定編程語言

在開頭標記後指定語言名稱啟用語法高亮:

markdown
```javascript
function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(fibonacci(10)); // 55
```

渲染效果

javascript
function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(fibonacci(10)); // 55

常用語言示例

Python

markdown
```python
def quicksort(arr):
    if len(arr) <= 1:
        return arr
    
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    
    return quicksort(left) + middle + quicksort(right)

# 示例使用
numbers = [3, 6, 8, 10, 1, 2, 1]
print(quicksort(numbers))
```

渲染效果

python
def quicksort(arr):
    if len(arr) <= 1:
        return arr
    
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    
    return quicksort(left) + middle + quicksort(right)

# 示例使用
numbers = [3, 6, 8, 10, 1, 2, 1]
print(quicksort(numbers))

TypeScript

markdown
```typescript
interface User {
    id: number;
    name: string;
    email: string;
    isActive: boolean;
}

class UserService {
    private users: User[] = [];

    async createUser(userData: Omit<User, 'id'>): Promise<User> {
        const newUser: User = {
            id: Date.now(),
            ...userData
        };
        
        this.users.push(newUser);
        return newUser;
    }

    async getUserById(id: number): Promise<User | undefined> {
        return this.users.find(user => user.id === id);
    }
}
```

渲染效果

typescript
interface User {
    id: number;
    name: string;
    email: string;
    isActive: boolean;
}

class UserService {
    private users: User[] = [];

    async createUser(userData: Omit<User, 'id'>): Promise<User> {
        const newUser: User = {
            id: Date.now(),
            ...userData
        };
        
        this.users.push(newUser);
        return newUser;
    }

    async getUserById(id: number): Promise<User | undefined> {
        return this.users.find(user => user.id === id);
    }
}

Go

markdown
```go
package main

import (
    "fmt"
    "net/http"
    "log"
)

type Server struct {
    port string
}

func NewServer(port string) *Server {
    return &Server{port: port}
}

func (s *Server) Start() error {
    http.HandleFunc("/", s.handleHome)
    http.HandleFunc("/api/health", s.handleHealth)
    
    fmt.Printf("Server starting on port %s\n", s.port)
    return http.ListenAndServe(":"+s.port, nil)
}

func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Welcome to Go Server!")
}

func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    fmt.Fprintf(w, `{"status": "healthy"}`)
}

func main() {
    server := NewServer("8080")
    log.Fatal(server.Start())
}
```

渲染效果

go
package main

import (
    "fmt"
    "net/http"
    "log"
)

type Server struct {
    port string
}

func NewServer(port string) *Server {
    return &Server{port: port}
}

func (s *Server) Start() error {
    http.HandleFunc("/", s.handleHome)
    http.HandleFunc("/api/health", s.handleHealth)
    
    fmt.Printf("Server starting on port %s\n", s.port)
    return http.ListenAndServe(":"+s.port, nil)
}

func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Welcome to Go Server!")
}

func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    fmt.Fprintf(w, `{"status": "healthy"}`)
}

func main() {
    server := NewServer("8080")
    log.Fatal(server.Start())
}

高級功能

行高亮

某些 Markdown 處理器支持高亮特定行:

markdown
```javascript {2,4-6}
function calculateTotal(items) {
    let total = 0; // 這行被高亮
    
    for (const item of items) { // 這幾行被高亮
        total += item.price * item.quantity;
    } // 高亮結束
    
    return total;
}
```

行號顯示

顯示代碼行號:

markdown
```python:line-numbers
def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    
    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    
    return -1
```

文件名標題

顯示代碼文件名:

markdown
```typescript title="userService.ts"
export class UserService {
    private apiUrl = '/api/users';

    async getUsers(): Promise<User[]> {
        const response = await fetch(this.apiUrl);
        return response.json();
    }

    async createUser(user: CreateUserDto): Promise<User> {
        const response = await fetch(this.apiUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(user)
        });
        return response.json();
    }
}
```

代碼塊差異顯示

顯示代碼變更:

markdown
```diff
function calculateTax(amount) {
-   return amount * 0.05; // 舊的稅率
+   return amount * 0.08; // 新的稅率
}

+ // 新增的函數
+ function calculateDiscount(amount, percentage) {
+     return amount * (percentage / 100);
+ }
```

渲染效果

diff
function calculateTax(amount) {
-   return amount * 0.05; // 舊的稅率
+   return amount * 0.08; // 新的稅率
}

+ // 新增的函數
+ function calculateDiscount(amount, percentage) {
+     return amount * (percentage / 100);
+ }

配置文件示例

JSON 配置

markdown
```json
{
  "name": "my-app",
  "version": "1.0.0",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "build": "webpack --mode production",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.0.3",
    "jsonwebtoken": "^9.0.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.22",
    "jest": "^29.5.0",
    "webpack": "^5.82.0"
  }
}
```

渲染效果

json
{
  "name": "my-app",
  "version": "1.0.0",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "build": "webpack --mode production",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.0.3",
    "jsonwebtoken": "^9.0.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.22",
    "jest": "^29.5.0",
    "webpack": "^5.82.0"
  }
}

YAML 配置

markdown
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web
        image: nginx:1.21
        ports:
        - containerPort: 80
        env:
        - name: NODE_ENV
          value: production
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
```

渲染效果

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web
        image: nginx:1.21
        ports:
        - containerPort: 80
        env:
        - name: NODE_ENV
          value: production
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

SQL 查詢

markdown
```sql
-- 創建用戶表
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 創建索引
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_username ON users(username);

-- 查詢活躍用戶
SELECT 
    u.id,
    u.username,
    u.email,
    COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
WHERE u.created_at >= NOW() - INTERVAL '30 days'
GROUP BY u.id, u.username, u.email
HAVING COUNT(p.id) > 0
ORDER BY post_count DESC
LIMIT 10;
```

渲染效果

sql
-- 創建用戶表
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 創建索引
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_username ON users(username);

-- 查詢活躍用戶
SELECT 
    u.id,
    u.username,
    u.email,
    COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
WHERE u.created_at >= NOW() - INTERVAL '30 days'
GROUP BY u.id, u.username, u.email
HAVING COUNT(p.id) > 0
ORDER BY post_count DESC
LIMIT 10;

Shell 腳本和命令

Bash 腳本

markdown
```bash
#!/bin/bash

# 部署腳本
set -e

APP_NAME="my-app"
DEPLOY_DIR="/var/www/${APP_NAME}"
BACKUP_DIR="/var/backups/${APP_NAME}"
CURRENT_DATE=$(date +%Y%m%d_%H%M%S)

echo "開始部署 ${APP_NAME}..."

# 創建備份
if [ -d "$DEPLOY_DIR" ]; then
    echo "創建備份到 ${BACKUP_DIR}/${CURRENT_DATE}"
    mkdir -p "$BACKUP_DIR"
    cp -r "$DEPLOY_DIR" "${BACKUP_DIR}/${CURRENT_DATE}"
fi

# 停止服務
echo "停止服務..."
sudo systemctl stop $APP_NAME || true

# 部署新版本
echo "部署新版本..."
rm -rf "$DEPLOY_DIR"
mkdir -p "$DEPLOY_DIR"
tar -xzf "${APP_NAME}.tar.gz" -C "$DEPLOY_DIR"

# 安裝依賴
echo "安裝依賴..."
cd "$DEPLOY_DIR"
npm ci --production

# 啟動服務
echo "啟動服務..."
sudo systemctl start $APP_NAME
sudo systemctl enable $APP_NAME

echo "部署完成!"
```

渲染效果

bash
#!/bin/bash

# 部署腳本
set -e

APP_NAME="my-app"
DEPLOY_DIR="/var/www/${APP_NAME}"
BACKUP_DIR="/var/backups/${APP_NAME}"
CURRENT_DATE=$(date +%Y%m%d_%H%M%S)

echo "開始部署 ${APP_NAME}..."

# 創建備份
if [ -d "$DEPLOY_DIR" ]; then
    echo "創建備份到 ${BACKUP_DIR}/${CURRENT_DATE}"
    mkdir -p "$BACKUP_DIR"
    cp -r "$DEPLOY_DIR" "${BACKUP_DIR}/${CURRENT_DATE}"
fi

# 停止服務
echo "停止服務..."
sudo systemctl stop $APP_NAME || true

# 部署新版本
echo "部署新版本..."
rm -rf "$DEPLOY_DIR"
mkdir -p "$DEPLOY_DIR"
tar -xzf "${APP_NAME}.tar.gz" -C "$DEPLOY_DIR"

# 安裝依賴
echo "安裝依賴..."
cd "$DEPLOY_DIR"
npm ci --production

# 啟動服務
echo "啟動服務..."
sudo systemctl start $APP_NAME
sudo systemctl enable $APP_NAME

echo "部署完成!"

常見錯誤和解決方案

1. 反引號數量不匹配

markdown
❌ 錯誤:
```javascript
function hello() {
    console.log("Hello");
}
``  ← 只有兩個反引號

✅ 正確:
```javascript
function hello() {
    console.log("Hello");
}
```  ← 三個反引號

2. 語言標識符錯誤

markdown
❌ 錯誤:
```js  ← 某些處理器不識別
function hello() {}
```

✅ 推薦:
```javascript  ← 使用完整名稱
function hello() {}
```

3. 嵌套代碼塊

markdown
❌ 問題:無法顯示包含 ``` 的代碼

✅ 解決:使用四個反引號包裝三個反引號
````markdown
```javascript
console.log("hello");
```

### 4. 特殊字符處理

````markdown
```markdown
<!-- 在 markdown 代碼塊中顯示 markdown 語法 -->
\```javascript  ← 轉義反引號
code here
\```
```

支持的語言列表

編程語言

語言標識符別名
JavaScriptjavascriptjs
TypeScripttypescriptts
Pythonpythonpy
Javajava
C++cppc++, cxx
C#csharpcs
Gogogolang
Rustrustrs
PHPphp
Rubyrubyrb
Swiftswift
Kotlinkotlinkt

標記和配置語言

語言標識符用途
HTMLhtml網頁標記
CSScss樣式表
XMLxml數據交換
JSONjson數據格式
YAMLyaml, yml配置文件
TOMLtoml配置文件
Markdownmarkdown, md文檔編寫

數據和查詢語言

語言標識符用途
SQLsql數據庫查詢
GraphQLgraphqlAPI查詢
Rr統計計算
MATLABmatlab數值計算

Shell 和腳本

語言標識符用途
Bashbash, shUnix Shell
PowerShellpowershell, ps1Windows Shell
Batchbatch, batWindows 批處理
Dockerfiledockerfile容器配置

最佳實踐

1. 選擇合適的語言標識符

markdown
✅ 推薦:使用准確的語言標識符
```typescript
interface User {
    id: number;
    name: string;
}
```

❌ 不推薦:使用錯誤的標識符
```javascript  ← 這是 TypeScript 代碼
interface User {
    id: number;
    name: string;
}
```

2. 添加有意義的注釋

markdown
✅ 推薦:包含解釋性注釋
```python
def fibonacci(n):
    """計算斐波那契數列的第n項"""
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)
```

❌ 不推薦:缺少說明的代碼
```python
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)
```

3. 保持代碼簡潔

markdown
✅ 推薦:展示核心邏輯
```javascript
// 用戶認證中間件
function authenticate(req, res, next) {
    const token = req.headers.authorization;
    if (!token) {
        return res.status(401).json({ error: 'No token provided' });
    }
    // 驗證邏輯...
    next();
}
```

❌ 不推薦:包含過多細節
```javascript
// 省略大量無關代碼...
```

4. 使用文件名標題

markdown
✅ 推薦:顯示文件名
```javascript title="middleware/auth.js"
export function authenticate(req, res, next) {
    // 認證邏輯
}
```

✅ 推薦:顯示配置文件名
```json title="package.json"
{
  "name": "my-app",
  "version": "1.0.0"
}
```

實際應用場景

1. API 文檔

markdown
## 用戶登錄 API

**請求示例:**

```bash
curl -X POST https://api.example.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "password123"
  }'
```

**響應示例:**

```json
{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": 1,
      "email": "user@example.com",
      "name": "張三"
    }
  }
}
```

**錯誤響應:**

```json
{
  "success": false,
  "error": {
    "code": "INVALID_CREDENTIALS",
    "message": "Invalid email or password"
  }
}
```

2. 安裝教程

markdown
## 環境配置

### 1. 安裝 Node.js

**macOS (使用 Homebrew):**

```bash
# 安裝 Homebrew(如果還沒有)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 安裝 Node.js
brew install node

# 驗證安裝
node --version
npm --version
```

**Ubuntu/Debian:**

```bash
# 更新包列表
sudo apt update

# 安裝 Node.js 和 npm
sudo apt install nodejs npm

# 驗證安裝
node --version
npm --version
```

**Windows (使用 Chocolatey):**

```powershell
# 安裝 Chocolatey(使用管理員權限)
Set-ExecutionPolicy Bypass -Scope Process -Force; 
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

# 安裝 Node.js
choco install nodejs

# 驗證安裝
node --version
npm --version
```

3. 代碼對比

markdown
## 重構前後對比

**重構前(回調地獄):**

```javascript
function getUserData(userId, callback) {
    getUser(userId, function(err, user) {
        if (err) {
            callback(err);
            return;
        }
        
        getPosts(user.id, function(err, posts) {
            if (err) {
                callback(err);
                return;
            }
            
            getComments(posts[0].id, function(err, comments) {
                if (err) {
                    callback(err);
                    return;
                }
                
                callback(null, { user, posts, comments });
            });
        });
    });
}
```

**重構後(async/await):**

```javascript
async function getUserData(userId) {
    try {
        const user = await getUser(userId);
        const posts = await getPosts(user.id);
        const comments = await getComments(posts[0].id);
        
        return { user, posts, comments };
    } catch (error) {
        throw error;
    }
}
```

HTML 輸出

圍欄代碼塊轉換為 HTML:

markdown
```javascript
function hello() {
    console.log("Hello");
}
```

轉換為:

html
<pre><code class="language-javascript">
function hello() {
    console.log("Hello");
}
</code></pre>

相關語法

練習

嘗試創建以下代碼塊:

  1. 一個包含多種編程語言的代碼示例集合
  2. 一個完整的 API 使用教程(包含請求和響應)
  3. 一個部署腳本的說明文檔
  4. 一個數據庫設計的 SQL 腳本

工具和插件

語法高亮庫

  • Prism.js: 輕量級語法高亮
  • highlight.js: 功能豐富的高亮庫
  • CodeMirror: 在線代碼編輯器
  • Monaco Editor: VS Code 編輯器核心

Markdown 處理器

  • markdown-it: 可擴展的 Markdown 解析器
  • remark: 統一的 Markdown 處理器
  • marked: 快速的 Markdown 解析器
  • gray-matter: Front Matter 解析

編輯器插件

  • VS Code: Markdown Preview Enhanced
  • Sublime Text: MarkdownEditing
  • Atom: markdown-preview-plus
  • Vim: vim-markdown

由 Markdownlang.com 整理創建