13 | 編寫markdown編輯器時遇到的冷知識

這里是在簡書仿簡書的第十三篇杉适,早睡早起身體好

Vue3 版本在線預覽 https://shuhe.cemcoe.com/

前段時間在搞在簡書仿簡書霹娄,這個問題的核心點在哪呢初斑?或者說核心是什么屯蹦?

僅就個人主觀感受,大部分人夸簡書的點一般是簡潔的編輯器笛园,黑的點大概就是首頁推薦機制了懦胞,那,核心是編輯器咯脊串。

在使用 Vue2 寫的時候在 markdown 編輯器這塊直接選用了一個組件辫呻,在使用 Vue3 重寫時清钥,不打算用外部組件了,來看一波核心放闺,搞一個 markdown 編輯器祟昭。于是就有了下面的冷知識。


先來想一下 markdown 編輯器的功能點怖侦,最重要的就是將 markdown 格式渲染成 html 了篡悟,簡言之,要完成下面的轉化匾寝。

# => h1
![]() => img
[]() => a
搬葬。。艳悔。

好辦呀急凰,思路是使用正則找特殊標志位比如 # 號,再使用字符串的一些方法轉換成 html 格式的字符串猜年。以語句 # 我要轉化h1 為例抡锈,找到 # 號和后面的文字,使用 h1 標簽包裹就得到了 html 格式的字符串了乔外。

看起來好像很容易的樣子呢床三,但事情遠沒有那么簡單,markdown 語法對于 # 的使用是有規(guī)定的袁稽,在非開頭使用是不會渲染成標題標簽的勿璃。還有 ##### 等格式推汽,單單一個 # 就夠頭疼的了补疑,更別說各種符號的排列組合了。這個從 markdown 到 html 的轉化的工作量還是很大的歹撒,而且也不是簡單的使用正則找到值再替換的過程莲组。這里面涉及到一些編譯原理的知識。老難搞了暖夭。

好在這個略顯“無聊”的工作已經有人幫我們做了锹杈,就像有人搞出來 babel 來幫我們完成 es6 到 es5 的轉化,已經有人搞出了 marked 來幫我們完成 markdown 到 html 的轉化迈着,當然還有其他的比如 markdownit竭望。

這里就使用 marked 了。其實還是沒有觸及到核心科技裕菠。翻看 marked 的源碼可以發(fā)現(xiàn)咬清,找字符或者術語一點叫做詞法分析階段確實用到的正則,具體可參考https://github.com/markedjs/marked/blob/master/src/rules.js

好的,第一項完成旧烧,現(xiàn)在在 textarea 寫 markdown影钉,點擊預覽調用 marked 方法。

<textarea
        v-model="content"
        name="post"
        id="post"
        placeholder="請輸入正文"
      ></textarea>

 <div class="preview" v-show="isPreview">
    <div v-html="previewContent"></div>
 </div>

<script>
import marked from "marked";
state.previewContent = marked(state.content);
</script>

如果要簡潔的話掘剪,其實這就搞好了平委。


如果要在移動端使用的話最好加點按鈕用于插入符號,畢竟在手機上一些 markdown 符號打起來不是很方便夺谁。

這里就涉及到一些冷知識了廉赔,插入符號換言之就是字符串拼接,字符串拼接是很常規(guī)的操作了予权,這里的核心是如何找到拼接點昂勉。

這里就需要用到一些光標的冷知識了,上圖扫腺。


Snipaste_2021-02-03_11-05-56.png
[post.selectionStart, post.selectionEnd]

通過上面的圖大概就可以明白這兩個屬性的意思了岗照。那么插入的邏輯就好搞了。

找到光標的位置接下來就好辦了笆环,甭管你用什么法子攒至,把字符串從光標位置劈開往里面插入符號。

let start = dom.selectionStart
let end = dom.selectionEnd
dom.value = dom.value.substring(0, start) + string + dom.value.substring(end, dom.value.length)

看起來完成了需求躁劣,誒迫吐,別急,當你點擊按鈕插入符號后账忘,你會發(fā)現(xiàn) textarea 中光標沒有了志膀,此時如果你再次點擊插入操作會有什么現(xiàn)象呢?它會插到最前面鳖擒。

demo.gif

光標消失的原因吧溉浙,其實很簡單,就是本來 textarea 是處于激活狀態(tài)蒋荚,而當你點擊插入按鈕時焦點移交給了按鈕戳稽,自然 textarea 就沒有光標了。

既然如此期升,當插入完畢時我們將焦點再次移交給 textarea 就好了惊奇。

dom.focus()

此時你會發(fā)現(xiàn)另一個問題,那就是光標的位置跑到了最后播赁。

demo1.gif

好家伙颂郎,從頭跑到尾了,要解決也很簡單容为。在找光標位置時已經用到了祖秒,再來诞吱,設置一下舟奠。

dom.selectionStart = start + string.length;
dom.selectionEnd = start + string.length;

再試一試應該就好了竭缝。

demo2.gif

這個 markdown 編輯器和 Vue 的關系不是很大,核心是 markdown 到 html 的轉化沼瘫。

代碼匯總后:

function useInsertText(dom, string) {
  let start = dom.selectionStart
  let end = dom.selectionEnd
  dom.value = dom.value.substring(0, start) + string + dom.value.substring(end, dom.value.length)
  dom.selectionStart = start + string.length;
  dom.selectionEnd = start + string.length;
  dom.focus()
}

在找資料時發(fā)現(xiàn)另一個方案抬纸,雖然已經廢棄,不過經測試還是好用的耿戚。

// 已廢棄湿故,不推薦,但無須解決焦點丟失和光標位置
document.execCommand('insertText', false, string)

這里的冷知識主要是光標相關的東西膜蛔,這玩意一般場景下用到的幾率確實也不是很多坛猪。

其實這里還是有一些待出來的東西在的,比如移動端的鍵盤皂股,當你點擊插入按鈕后墅茉,因為 textarea 失去焦點,軟鍵盤將會收起呜呐,只有 textarea 重新獲取焦點后鍵盤才會彈出就斤。此時就會頻繁出現(xiàn)鍵盤的收起和彈出。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末蘑辑,一起剝皮案震驚了整個濱河市洋机,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洋魂,老刑警劉巖绷旗,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異衔肢,居然都是意外死亡,警方通過查閱死者的電腦和手機址晕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門膀懈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谨垃,你說我怎么就攤上這事启搂。” “怎么了刘陶?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵胳赌,是天一觀的道長。 經常有香客問我匙隔,道長疑苫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮捍掺,結果婚禮上撼短,老公的妹妹穿的比我還像新娘。我一直安慰自己挺勿,他們只是感情好曲横,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著不瓶,像睡著了一般禾嫉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚊丐,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天熙参,我揣著相機與錄音,去河邊找鬼麦备。 笑死孽椰,一個胖子當著我的面吹牛,可吹牛的內容都是我干的泥兰。 我是一名探鬼主播弄屡,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鞋诗!你這毒婦竟也來了膀捷?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤削彬,失蹤者是張志新(化名)和其女友劉穎全庸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體融痛,經...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡壶笼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了雁刷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片覆劈。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沛励,靈堂內的尸體忽然破棺而出责语,到底是詐尸還是另有隱情,我是刑警寧澤目派,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布坤候,位于F島的核電站,受9級特大地震影響企蹭,放射性物質發(fā)生泄漏白筹。R本人自食惡果不足惜智末,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望徒河。 院中可真熱鬧系馆,春花似錦、人聲如沸虚青。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棒厘。三九已至,卻和暖如春下隧,著一層夾襖步出監(jiān)牢的瞬間奢人,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工淆院, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留何乎,地道東北人。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓土辩,卻偏偏與公主長得像支救,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拷淘,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內容