9102年如何写一个自己的markdown在线编辑器

Markdown 在线编辑器

先贴出编辑器地址,涵盖了大多数markdown语法的快捷操作,实时编译实时预览,支持直接导出md 格式文件,支持微博图床。纯前端实现,不必担心数据被后台存储。未做移动端适配,建议pc食用。 欢迎各位有写作需求的大佬试用,提出宝贵意见。

背景 & 前言

市面上一些md编辑器 有的有实时预览,比如掘金,没有操作按钮(有快捷键的哈),用着不是太方便,而简书的操作按钮有的受限于简书钻的数量。事实上有道词典的md编辑器做的很好,但最近出现了我出现了卡顿、中文难以输入上去的问题,弃之。
所以干脆自己撸一个,可以满足自己写东西的需求。 自己做的东西就算难用也得受着
由于手上没有windows设备,滚动条的样式还请自己修改下。


技术

vue less iview markdown-it iconfont


插件

markdown-it-mark 标记功能
markdown-it-emoji emoji表情解析
highligh.js代码高亮
markdown-it-task-checkbox 复选框功能
markdown-it-footnote 脚注功能


插件效果

==高亮标记==
:smiling_imp:

掘金没有支持标记emoji,贴一下图。

原理

在编辑器输入组件中 watch输入内容的变化,有变化就实时调用markdown-itrender函数,并在localStorage中实时更新一份,防止页面误操作被跳出再返回时辛辛苦苦写的内容没了。同时也可以达到这次没写完页面关闭了,下次打开继续写的需求。 导出文件后草稿会被清空。 因为不调用接口存储数据,未做函数防抖处理,如需引入请自行添加。 微博图床的地址是从一个工具页面上扒下来的,感觉写那个工具的兄弟也是从其他的地方扒的呢哈哈(开玩笑的),贴出工具地址:图床工具


下载打包

git clone [email protected]:ch957869975/md-editor.git
npm run devnpm run build 打开 8080端口即可看到预览


有意思的点

做的时候遇到几个点比较有意思,提一下。

在光标位置插入字符

ie 支持document.selection,而绝大多数浏览器支持selectionStartselectionEnd 两个属性。利用这两个属性加上字符串的substring方法动态拼接起来。 这里需要注意的是 用这个方法拼接起来的字符串,并没有触发对变量的双向绑定,所以我在这里手动触发了一下textarea的input事件,如下:

 document.querySelector('textarea').dispatchEvent(new Event('input'))
复制代码

文件在前端生成并下载

下载在前端开发中并不稀奇,但文件写入可能不常遇到,要不是写这个玩意,我也没做过文件生成。 代码如下:

if (!this.editorContent || !window.localStorage.getItem('MarkdownDraft')) {
     return this.$Notice.error({ title: '你还没有写内容' })
 }
const content = this.editorContent
const elem = document.createElement('a');
elem.download = 'draft.md';
elem.style.display = 'none';
const blob = new Blob([content], { type: 'text/plain' });
elem.href = URL.createObjectURL(blob)
document.body.appendChild(elem);
elem.click();
document.body.removeChild(elem);
setTimeout(() => {
   this.editorContent = ''
   window.localStorage.removeItem('MarkdownDraft')
}, 300)
复制代码

思路还是比较清晰的:有值的时候才生成, 避免生成一个空文件。 利用Blob对象生成对应内容后,再创建一个 不可见的a标签并将 hrefdownload属性添加进去,手动触发点击事件后并移除该标签。 但是需要考虑兼容性呀。 这里是a.download的支持情况,ie不支持!!!。

木得办法,做个判断吧。

 if (!('download' in document.createElement('a'))) return this.$Notice.error({ title: '浏览器不支持' })
复制代码

可能你说ie怎么办?
回答:都9102年了,你还在用ie,不抛弃你抛弃谁??


组件通信

组件之间通信,因为偷懒,用了bus.js,实际代码就两行

import Vue from 'vue'
export default new Vue()
复制代码

原理是 挂载在同一实例上的组件都可以触发实例上的事件,理论上是可以实现任意组件之间的通信,无视组件层级关系。但是, 并不推荐这种做法,因为这会让你的逻辑太跳跃,具体表现就是你的代码东一榔头西一棒子,A组件在bus上绑定的事件经常找不到在哪里触发的,B组件触发的事件找不到是在哪里绑定的,维护起来较为困难。


总结

功能简单、技术简单、ui简单、部署简单。一个简单的小项目,就看你愿不愿意去做了。

这里贴出编辑器地址源码地址厚着脸皮求个star博客地址

不是所有的事情都能如愿以偿,但是任何事情都值得去尝试。加油!

ps: 下面两个脚注对应插件效果演示,不必关心。


  1. 脚注1 ↩︎

  2. 脚注2 ↩︎

猜你喜欢

转载自juejin.im/post/5c679c7051882562c955d9b1