13 | 编写markdown编辑器时遇到的冷知识

这里是在简书仿简书的第十三篇,早睡早起身体好

Vue3 版本在线预览 https://shuhe.cemcoe.com/

前段时间在搞在简书仿简书,这个问题的核心点在哪呢?或者说核心是什么?

仅就个人主观感受,大部分人夸简书的点一般是简洁的编辑器,黑的点大概就是首页推荐机制了,那,核心是编辑器咯。

在使用 Vue2 写的时候在 markdown 编辑器这块直接选用了一个组件,在使用 Vue3 重写时,不打算用外部组件了,来看一波核心,搞一个 markdown 编辑器。于是就有了下面的冷知识。


先来想一下 markdown 编辑器的功能点,最重要的就是将 markdown 格式渲染成 html 了,简言之,要完成下面的转化。

# => h1
![]() => img
[]() => a
。。。

好办呀,思路是使用正则找特殊标志位比如 # 号,再使用字符串的一些方法转换成 html 格式的字符串。以语句 # 我要转化h1 为例,找到 # 号和后面的文字,使用 h1 标签包裹就得到了 html 格式的字符串了。

看起来好像很容易的样子呢,但事情远没有那么简单,markdown 语法对于 # 的使用是有规定的,在非开头使用是不会渲染成标题标签的。还有 ##### 等格式,单单一个 # 就够头疼的了,更别说各种符号的排列组合了。这个从 markdown 到 html 的转化的工作量还是很大的,而且也不是简单的使用正则找到值再替换的过程。这里面涉及到一些编译原理的知识。老难搞了。

好在这个略显“无聊”的工作已经有人帮我们做了,就像有人搞出来 babel 来帮我们完成 es6 到 es5 的转化,已经有人搞出了 marked 来帮我们完成 markdown 到 html 的转化,当然还有其他的比如 markdownit。

这里就使用 marked 了。其实还是没有触及到核心科技。翻看 marked 的源码可以发现,找字符或者术语一点叫做词法分析阶段确实用到的正则,具体可参考https://github.com/markedjs/marked/blob/master/src/rules.js

好的,第一项完成,现在在 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 符号打起来不是很方便。

这里就涉及到一些冷知识了,插入符号换言之就是字符串拼接,字符串拼接是很常规的操作了,这里的核心是如何找到拼接点。

这里就需要用到一些光标的冷知识了,上图。


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)

看起来完成了需求,诶,别急,当你点击按钮插入符号后,你会发现 textarea 中光标没有了,此时如果你再次点击插入操作会有什么现象呢?它会插到最前面。

demo.gif

光标消失的原因吧,其实很简单,就是本来 textarea 是处于激活状态,而当你点击插入按钮时焦点移交给了按钮,自然 textarea 就没有光标了。

既然如此,当插入完毕时我们将焦点再次移交给 textarea 就好了。

dom.focus()

此时你会发现另一个问题,那就是光标的位置跑到了最后。

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()
}

在找资料时发现另一个方案,虽然已经废弃,不过经测试还是好用的。

// 已废弃,不推荐,但无须解决焦点丢失和光标位置
document.execCommand('insertText', false, string)

这里的冷知识主要是光标相关的东西,这玩意一般场景下用到的几率确实也不是很多。

其实这里还是有一些待出来的东西在的,比如移动端的键盘,当你点击插入按钮后,因为 textarea 失去焦点,软键盘将会收起,只有 textarea 重新获取焦点后键盘才会弹出。此时就会频繁出现键盘的收起和弹出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容