痞客邦部落格程式上色相關文章:

Prism.js



網址: https://prismjs.com/

最近 (2024/09) 無意間看到介紹 Prism.js 的文章, 現下來試試, 看看是否比 highlight.js 好用.


個人大致看完 prism.js 網站上的說明, 除了基本的上色功能之外, 還有一個自動載入程式 (auto loader) 及許許多多的 plugin (叫我看得眼花撩亂). 總之, 不是我習慣的風格. 不過沒關係, 反正就試用一下應該不成問題.

基本上色功能


  • 和 hljs 一樣, 它的上色主要對象是用 <pre>+<code> 這二個 tag 括住的程式片斷. 還有, 夾雜在一般文字段內的 <code> 片斷, 只要指定其上色的語言, 它也可以為之上色.
  • 然後要在 <code> 上使用 class="language-xxxx" 或者 class="lang-xxxx" 指定要上色的語言.
  • 要上色的第一行程式必需立即接在 <code> tag 後面.
  • 程式的最後一行後面也最好立即接上 </code>
<pre><code class="language-CPP">從這裡開始寫你要上色的程式碼
...
你要上色的程式碼
...</code>
</pre>

和其他上色套件一樣, 使用前先載人它的核心套件及上色主題 (theme). 不過, 它的官方上色主題只有少數幾種 (不似 hljs 那樣種類繁多, 令人眼花撩亂). 另外, github 上的 "Prism Themes" 這個 repository 上面收集了不少用戶提供的上色主題, 它一樣可以由各大 cdn 下載.

<!-- Prism 上色主題的載入路徑 -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
<!-- Prism-themes 上色主題的載入路徑 -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism-themes/1.9.0/prism-a11y-dark.min.css" rel="stylesheet" />
<!-- 載入上色主題 -->
<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css" rel="stylesheet" />
<!-- 載入 Prism.js -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<!-- 接著載入其他語言模組 -->

除了上述的標準寫法, prism.js 官方有提供自動載入程式, 可以協助我們載入整個頁面中使用到的其他語言 (即: 不必自己載入需要的上色語言模組). 使用時, 我們只需載入 prism.js 的核心元件: components/prism-core.min.js自動載入插件: plugins/autoloader/prism-autoloader.min.js, 其他需用到的語言模組不必自行載入.

<!-- 載入上色主題 -->
<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css" rel="stylesheet" />
<!-- 只載入 Prism.js 核心元件 -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
<!-- 載入 autoloader -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>

不過個入發現 autoloader 對 html+css+js 三者混合的程式片斷判定不是很精準, 所以我們可以把核心元件部份改回 prism.js, 然後一樣用 autoloader 為我們載入其他的語言模組, 如下:

<!-- 載入上色主題 -->
<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css" rel="stylesheet" />
<!-- 載入 Prism.js -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<!-- 載入 autoloader -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>

附加行號


和 hljs 一樣, 附加行號功能是由插件提供的.

<!-- 載入插件 '附加行號' 的 CSS -->
<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css" rel="stylesheet" />
<!-- 載入插件 '附加行號' -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
  • 然後為需要附加行號的 <pre> tag 加上 class='line-numbers'.
  • 也可以在一個範圍比較大的區塊上附加 class='line-numbers', 這樣可以省去為區塊內的每一個 <pre> tag 加上 class='line-numbers'.
    • 沒有現成的大區塊, 則可以在需要的範圍上外加一個 <div class='line-numbers'> tag 包住它們.
    • 區塊內如果有不想附上行號的 <pre> tag, 則加上 class='no-line-numbers'.
  • 指定行號的起始值需要在 <pre> tag 上附加上 data-start='起始值' 的屬性. 例如, 行號由 7 開始: <pre data-start='7'>

附加拷貝按鈕


拷貝按鈕功能也是由插件提供, 不過它需要另一個叫 toolbar 的插件.

<!-- 載入插件 'toolbar' 的 CSS -->
<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css" rel="stylesheet" />
<!-- 載入插件 'toolbar' -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
<!-- 載入插件 '拷貝按鈕' -->
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>

拷貝按鈕可以用 HTML tag 的屬性進行設定. 總共有三個狀態訊息及一個計時器設定, 我們可以在 <pre> tag 對它進行訊息本地化及設定調整. 或者也可以像附加行號的插件一樣, 將設定搬到一個範圍比較大的上層 <div> 區塊.

  • data-prismjs-copy: 預設訊息, 尚未拷貝狀態.
    正體中文本地化應將此訊息設為 "複製" 或者 "拷貝" 等類似詞語.
  • data-prismjs-copy-error: 拷貝錯誤訊息.
    正體中文本地化應將此訊息設為 "按 Ctrl+C, 複製" 或類似詞語.
  • data-prismjs-copy-success: 拷貝成功訊息.
    正體中文本地化應將此訊息設為 "已複製" 或類似詞語.
  • data-prismjs-copy-timeout: 拷貝成功/錯誤訊息的持續時間 (單位為 ms). 預設值為 5,000ms.

客製化按鈕外觀指南 (Styling)


我們可以為拷貝按鈕按鈕元件進行 CSS 客製化, 該按鈕元件的 HTML 如下:

<button class="copy-to-clipboard-button" type="button" data-copy-state="copy">
	<span>Copy</span>
</button>

使用 .copy-to-clipboard-button 可以定位到拷貝按鈕. 另外屬性 data-copy-state 有三個狀態:

  • data-copy-state="copy": 預設訊息, 尚未拷貝狀態.
  • data-copy-state="copy-error": 顯示拷貝錯誤訊息時.
  • data-copy-state="copy-success": 顯示拷貝成功訊息時.

使用 .copy-to-clipboard-button:not([data-copy-state="copy"]) 可以定位到非預設訊息的另外二個狀態.

小結


總結以上說明, 在部落格文章的後面貼上以下 HTML:

<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>

<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>

<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>

就可以使用 Prism.js 進行程式上色了.

Prism.js 客製化 CSS


在我自己的部落格中, Prism.js 免不了也是要客製化一下, 調整一下外觀. 由於和 pixnet 部落格衝突比較多, 所以我直接取消載入二個 plugin 的 CSS, 並直接將其內容抄到我的自訂 CSS 檔裡.

<link href="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>

在此我客製化了以下項目:

  • 修正痞客邦部落格行動版的三個 CSS 定位太大造成的影響.
  • 微調附加行號插件的外觀. (使用二個 CSS 變數)
  • 拷貝按鈕外觀改為 SVG 圖片. (這個是由 hljs 的 copy buttton 移值過來的, 工程好大)

最後的 myPrism.css 內容如下:

/* Fix for Pixnet Mobile */
.article-content-inner .tag span,
.article-content-inner .tag {
	background:revert;
	padding:revert;
	margin:revert;
	border-radius:revert;
	font-size:revert;
}
.article-content-inner .comment {
	font-family: revert;
	font-size:revert;
	padding:revert;
	border:revert;
	letter-spacing: revert;
}
.article-content-inner span { white-space:unset!important }

/* Adjustment for Prism line-number */
.article-content-inner {
	--ln-width:2.5em;
	--ln-rPad:0.5em;
}
pre[class*=language-] {
	margin:0!important;
	padding:0.25em!important;
}

/* From Prism line-number with patches */
pre[class*=language-].line-numbers {
	position: relative;
	padding-left:calc(var(--ln-width) + var(--ln-rPad))!important;
	counter-reset: linenumber
}
pre[class*=language-].line-numbers>code {
	position: relative;
	white-space: inherit
}
.line-numbers .line-numbers-rows {
	position: absolute;
	pointer-events: none;
	top: -2px;
	font-size: 100%;
	left: calc(0px - var(--ln-rPad) - var(--ln-width));
	width: var(--ln-width)!important;
	letter-spacing: -1px;
	border-right: 2px solid #999;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none
}
.line-numbers-rows>span {
	display: block;
	counter-increment: linenumber
}
.line-numbers-rows>span:before {
	content: counter(linenumber);
	color: #999;
	display: block;
	padding-right: var(--ln-rPad);
	text-align: right
}

/* Adjustment for Prism Copy button */
div.code-toolbar {
	position:relative;
	overflow:hidden;
	transform: translateZ(0)
}
div.code-toolbar>.toolbar {
	--theme-color: white;
	--theme-background: black;
	--theme-padding: 3.6px;
	position:absolute;
	top:0.25em;
	right:0.25em;
	transition:transform 200ms ease-out;
}
div.code-toolbar .toolbar-item>button {
	position: relative;
	margin: calc(var(--theme-padding) / 2);
	width: calc(16px + var(--theme-padding));
	height: calc(16px + var(--theme-padding));
	font-size: .8125rem;
	text-indent: -9999px;
	color: var(--theme-color);
	border-radius: .25rem;
	border: 1px solid;
	border-color: color-mix(in srgb,var(--theme-color),transparent 80%);
	background-color: var(--theme-background);
	transition: background-color 200ms ease;
	overflow: hidden
}
div.code-toolbar .toolbar-item>button[data-copy-state="copy"]::before {
	content: "";
	width: 1rem;
	height: 1rem;
	top: 50%;
	left: 50%;
	transform: translate(-50%,-50%);
	position: absolute;
	background-color: currentColor;
	mask: url('data:image/svg+xml;utf-8,');
	mask-repeat: no-repeat;
	mask-size: contain;
	mask-position: center center
}
.toolbar {
	transform: translateX(calc(100% + 1.125em))
}
div.code-toolbar:focus-within .toolbar {
	transition: none;
	transform: translateX(0)
}
div.code-toolbar:hover .toolbar {
	transform: translateX(0)
}
.toolbar-item>button:not([data-copy-state="copy"]) {
	text-indent: 0!important;
	width: auto!important;
}

試用心得


  • Prism.js 及其插件都不需額外的 JS 來啟動, 只用 HTML 的 tag 屬性來調整設定, 在部落格中 (非自行架設的) 使用上相對容易. highlight.js 比較麻煩一些, 不只 hljs 本身需要額外寫一行啟動用的 JS, 插件也需要用 addPlugin() 附加到 hljs 上.
  • Prism.js 支援 inline 上色 (即一般文字行中的 <code> tag), 無需額外的設定. highlight.js 目前的版本 (v11.10) 也支援 inline 上色. 不過,
    • 需要在上色前使用 hljs.configure({cssSelector: 'pre code, span code'}) 調整設定.
      • 此為個人測試時使用的, 非官方建議設定值.
    • 如果有使用附加行號的 highlightjs-line-numbers.js 插件並設定 {singleLine: true}, 則要多附加一個 class: nohljsln.
      • 因此, 個人建議直接關閉此設定值 (即不加, 或者設為 false).
    • 附加拷貝按鈕的 highlightjs-copy 插件: 暫時沒有關閉功能. 它一定會干擾到正常 hljs 的工作.
  • Prism.js 對 CSS Selector 的解析比較粗略, highlight.js 在此一部份比較精細.
arrow
arrow
    創作者介紹
    創作者 MagicJackTing 的頭像
    MagicJackTing

    傑克! 真是太神奇了!

    MagicJackTing 發表在 痞客邦 留言(0) 人氣()