自己動手刻一個 Markdown 編輯器!

大家平常在開發個人網站或後台系統的時候,說到「發文編輯器」,是不是第一直覺就是去 npm 裝個 TinyMCE 或是 CKEditor?
說真的,我一開始也想偷懶用套件。但裝完發現,那些肥大的 UI 介面不但吃資源,而且我平常寫 Code 早就習慣用 Markdown 了,為什麼寫個文章還要用滑鼠在那邊點「粗體」、「標題」點來點去?
所以心一橫,我決定不靠外掛,自己手刻一個工程師專用的 Markdown 編輯器!今天就來分享一下我是怎麼用 Vue 3 把它搞出來的。
🛠️ 準備工具
其實需要的東西很少,主軸就這三個:
- Vue 3 (Composition API):負責雙向綁定跟處理畫面連動。
- markdown-it:負責把 Markdown 語法即時翻譯成 HTML。
- highlight.js:工程師必備,讓文章裡的程式碼區塊有 VS Code 那種漂亮的高亮顏色。
🚀 第一步:超廢話的「即時預覽」
要做那種「左邊打字、右邊即時預覽」的效果,用 Vue 來寫根本是在作弊。我們完全不需要寫什麼複雜的監聽器,只要把左邊 textarea 的內容用 v-model 綁起來,然後寫個 computed 即時丟給 markdown-it 處理就好。
// 核心的預覽邏輯就這三行
const renderedContent = computed(() => {
// postForm.value.content 就是你輸入的純文字
return md.render(postForm.value.content);
});
然後在 HTML 裡面的預覽區塊加上 v-html="renderedContent",所見即所得的功能就打完收工了,有夠簡單。
🚀 第二步:有點搞人的「快捷工具列」
這是我覺得整段開發最好玩的地方。
當你反白一段文字,點擊工具列的「粗體」按鈕時,語法總不能傻傻地加在整篇文章最後面吧?它必須要剛好包住你選取的那段字,或是直接安插在游標現在停留的位置。
要做到這點,就得回去動用原生的 DOM API 了:
const insertMarkdown = (type) => {
if (!textareaRef.value) return;
const textarea = textareaRef.value; // 抓到 textarea 這個 DOM
const start = textarea.selectionStart; // 游標選取的開頭
const end = textarea.selectionEnd; // 游標選取的結尾
const text = postForm.value.content;
const selectedText = text.substring(start, end);
// 看你按了什麼按鈕,決定要塞什麼 Markdown 語法進去
let insertText = '';
switch (type) {
case 'bold': insertText = `**${selectedText || '粗體文字'}**`; break;
case 'h2': insertText = `## ${selectedText || '次標題'}\n`; break;
case 'code': insertText = `\`${selectedText || '程式碼'}\``; break;
}
// 關鍵:把原本的文章切成兩半,把新語法夾在中間,再黏回去!
postForm.value.content = text.substring(0, start) + insertText + text.substring(end);
// 貼心小優化:幫使用者把游標 focus 回去,才不用滑鼠重新點
setTimeout(() => {
textarea.focus();
textarea.setSelectionRange(start + insertText.length, start + insertText.length);
}, 0);
};
把這段加上去之後,整個編輯器瞬間有了靈魂,寫文章的節奏感超級順暢。
🎨 第三步:讓程式碼發光
技術文章如果沒有程式碼高亮,看的人會很痛苦。在初始化 markdown-it 的時候,順手把 highlight.js 整合進去:
const md = new MarkdownIt({
html: true,
linkify: true, // 自動把網址變成超連結
typographer: true,
highlight: function (str, lang) {
// 如果有標示語言,就套用 highlight.js 的樣式
if (lang && hljs.getLanguage(lang)) {
try {
return '<pre class="hljs"><code>' + hljs.highlight(str, { language: lang, ignoreIllegals: true }).value + '</code></pre>';
} catch (__) {}
}
// 找不到語言就退回基本款
return '<pre class="hljs"><code>' + escapeHtml(str) + '</code></pre>';
}
});
現在只要打上 ```javascript,右邊的預覽區馬上就有了專業的語法高亮,看了心情就很好。
🍻 說點真心話
市面上好用的開源編輯器套件真的多到數不清,隨便 npm install 一下就能動。但自己從零把這些功能拼湊起來,看到那個左右連動的畫面時,成就感真的不是套件能比的。
下次如果你的專案需要編輯器,別急著裝那些幾百 KB 的肥大外掛,自己手刻一個看看吧,真的沒那麼難!
