全部文章

NOTE 02 / 前端开发

Astro 与 Prism:给动态正文做代码高亮

拆开构建时与浏览器端两条路径,解决 CMS 正文和 Vue 组件的高亮时机。

Astro 构建时能高亮 Markdown 里的代码块。如果正文是从 CMS 拉出来,再用 Vue 的 v-html 渲染,代码块要在正文插入 DOM 后交给 Prism。

文章本身是 Markdown

Astro 默认使用 Shiki,换配色通常只需要改主题。如果想用 Prism,可在 Astro 配置中选择:

// astro.config.mjs
import { defineConfig } from 'astro/config'

export default defineConfig({
  markdown: { syntaxHighlight: 'prism' },
})

Prism 输出语法标记和 CSS 类。记得在公共布局加载主题,比如把 prism-okaidia.css 放到 public/styles/,再用 <link rel="stylesheet" href="/styles/prism-okaidia.css"> 引入。构建时已高亮的正文无需在浏览器里再扫描一次。

正文来自 CMS,通过 Vue 渲染

pnpm add prismjs
pnpm add -D @types/prismjs
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'
import Prism from 'prismjs'
import 'prismjs/themes/prism-okaidia.css'
import 'prismjs/components/prism-json'
import 'prismjs/components/prism-yaml'

const props = defineProps<{ html: string }>()
const article = ref<HTMLElement | null>(null)

function highlight() {
  if (article.value) Prism.highlightAllUnder(article.value)
}

onMounted(highlight)
watch(() => props.html, highlight, { flush: 'post' })
</script>

<template>
  <div ref="article" v-html="props.html"></div>
</template>

传给 v-html 的正文要可信,外部提交的 HTML 先做清洗。Astro 渲染这个组件时加 client:load,让 onMounted 在浏览器运行。highlightAllUnder 把扫描范围限制在正文里。

没有颜色时怎么查

  1. 确认 <pre><code> 上有 language-yaml 之类的语言标记,且对应语法已加载。
  2. 看 DOM 是否生成 span.token。有标记但没有颜色,就查主题 CSS。
  3. 首次进入正常、换文章后无效,检查高亮是否发生在正文更新之后。flush: 'post' 会在 DOM 更新后执行。

Astro 语法高亮说明 · Prism 使用文档

返回文章列表