哈囉,我1010

Hello, IIMGLHS

回列表

自己動手刻一個 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 的肥大外掛,自己手刻一個看看吧,真的沒那麼難!