前端开发经常会用到富文本编辑器,比如CKEditor,动不动一个库几十M的代码量,其中涉及许多你可能用不到的功能特性和相关设置,CKEditor最新版本的代码仓库就有接近2000个JS文件,300,000行代码。

可是如果你只需要一个简易版的编辑器,真的值得引入这么一个庞大的库吗?

今天我们从实现一个简易版的编辑器带大家了解一下其背后涉及到的原理。

开始

这个编辑器将要使用到markdown:一个简洁语法并且自带样式的语言,而且远比纯HTML的输入输出要安全得多。

首先,我们需要一些依赖包。 @ts-stack/markdown 和 turndown,@ts-stack/markdown是用来将markdown语法转化为HTML代码显示用的,而turndown是将HTML代码转化为markdown语言。

接下来,创建一个基础的Vue组件,命名为WysiwygEditor.vue,在组件中添加一个div元素,并且将它的contenteditable属性设置为true,然后添加一些Tailwind样式去美化一下。

<!-- WysiwygEditor.vue -->
<template><div><div@input="onInput"v-html="innerValue"contenteditable="true"class="wysiwyg-output outline-none border-2 p-4 rounded-lg border-gray-300 focus:border-green-300"/></div>
</template><script>
export default {name: 'WysiwygEditor',props: ['value'],data() {return {innerValue: this.value}},methods: {onInput(event) {this.$emit('input', event.target.innerHTML)}}
}
</script>

然后使用该组件:

<!-- Some other component -->
<template><!-- ... --><wysiwyg-editor v-model="someText" /><!-- ... -->
</template>
<!-- ... -->

看起来像这样

现在这个div元素的样式看起来像textarea 标签的效果了。

让文本变为富文本

在编辑器的上面会有一些带有bold,italic,underlined,headings,lists等文本的编辑按钮。并且上面会有对应功能的图标。可以通过安装fontawesome icon来实现。然后对按钮进行一些样式设置。

.button {@apply border-2;@apply border-gray-300;@apply rounded-lg;@apply px-3 py-1;@apply mb-3 mr-3;
}
.button:hover {@apply border-green-300;
}

先将这些按钮添加鼠标点击后的监听方法,后面我们会去实现每一个方法里的具体执行。

<!-- WysiwygEditor.vue -->
<template><!-- ... --><div class="flex flex-wrap"><button @click="applyBold" class="button"><font-awesome-icon :icon="['fas', 'bold']" /></button><button @click="applyItalic" class="button"><font-awesome-icon :icon="['fas', 'italic']" /></button><button @click="applyHeading" class="button"><font-awesome-icon :icon="['fas', 'heading']" /></button><button @click="applyUl" class="button"><font-awesome-icon :icon="['fas', 'list-ul']" /></button><button @click="applyOl" class="button"><font-awesome-icon :icon="['fas', 'list-ol']" /></button><button @click="undo" class="button"><font-awesome-icon :icon="['fas', 'undo']" /></button><button @click="redo" class="button"><font-awesome-icon :icon="['fas', 'redo']" /></button></div><!-- ... -->
</template>
<!-- ... -->

编辑器现在看起来是这样了

现在看起来是不是越来越接近了。还缺少按钮动作的执行方法。这里要用到document.execCommand,虽然MDN已经宣称将废弃该特性,但是大部分浏览器仍然支持。我们暂且还是使用它。

让我们通过它来实现applyBold方法

methods: {// ...applyBold() {document.execCommand('bold')},// ...
}

非常简洁明了,同样,我们来实现其它方法

// ...applyItalic() {document.execCommand('italic')},applyHeading() {document.execCommand('formatBlock', false, '<h1>')},applyUl() {document.execCommand('insertUnorderedList')},applyOl() {document.execCommand('insertOrderedList')},undo() {document.execCommand('undo')},redo() {document.execCommand('redo')}// ...

这里唯一需要说明的是applyHeading,因为我明确需要在此处指定所需的元素。使用这些命令后,可以预先对输出的元素标签进行一些样式设置

.wysiwyg-output h1 {@apply text-2xl;@apply font-bold;@apply pb-4;
}
.wysiwyg-output p {@apply pb-4;
}
.wysiwyg-output p {@apply pb-4;
}
.wysiwyg-output ul {@apply ml-6;@apply list-disc;
}
.wysiwyg-output ol {@apply ml-6;@apply list-decimal;
}

有了一定样式后,在输入框中输入一些内容

为了使得更美观一点,把空行用空的段落标签代替,以回车结束的内容归为一个段落

 // ...data() {return {innerValue: this.value || '<p><br></p>'}},mounted() {document.execCommand('defaultParagraphSeparator', false, 'p')},// ...

添加markdown支持

如果我想直接在编辑器里写markdown语法,暂时还不支持

# Hello, world!**Lorem ipsum dolor** _sit amet_* Some
* Unordered
* List1. Some
1. Ordered
1. List

结果看起来是这样

完全没有任何样式。别忘了,前面我们安装了@ts-stack/markdown库,现在可以使用了

import { Marked } from '@ts-stack/markdown'export default {name: 'WysiwygEditor',props: ['value'],data() {return {innerValue: Marked.parse(this.value) || '<p><br></p>'}},// ...

我们把输入的内容markdown语法转化为HTML代码之后,看起就正常了

同时还需要在组件传出本文编辑器数据的时候,进行转化,这里要用到前面安装的turndown

import TurndownService from 'turndown'export default {// ...methods: {onInput(event) {const turndown = new TurndownService({emDelimiter: '_',linkStyle: 'inlined',headingStyle: 'atx'})this.$emit('input', turndown.turndown(event.target.innerHTML))},
// ...

让我们把编辑器中输入的markdown语法文本在页面中通过模板输出后的效果

<!-- Some other component -->
<template><!-- ... --><wysiwyg-editor v-model="someText" /><pre class="p-4 bg-gray-300 mt-12">{{ someText }}</pre><!-- ... -->
</template>

同步输入输出,内容是一致的,没有任何问题

看起来一切正常,达到了我们想要的效果。下面是全部的代码

<template><div><div class="flex flex-wrap"><button @click="applyBold" class="button"><font-awesome-icon :icon="['fas', 'bold']" /></button><button @click="applyItalic" class="button"><font-awesome-icon :icon="['fas', 'italic']" /></button><button @click="applyHeading" class="button"><font-awesome-icon :icon="['fas', 'heading']" /></button><button @click="applyUl" class="button"><font-awesome-icon :icon="['fas', 'list-ul']" /></button><button @click="applyOl" class="button"><font-awesome-icon :icon="['fas', 'list-ol']" /></button><button @click="undo" class="button"><font-awesome-icon :icon="['fas', 'undo']" /></button><button @click="redo" class="button"><font-awesome-icon :icon="['fas', 'redo']" /></button></div><div@input="onInput"v-html="innerValue"contenteditable="true"class="wysiwyg-output outline-none border-2 p-4 rounded-lg border-gray-300 focus:border-green-300"/></div>
</template><script>
import { Marked } from '@ts-stack/markdown'
import TurndownService from 'turndown'export default {name: 'WysiwygEditor',props: ['value'],data() {return {innerValue: Marked.parse(this.value) || '<p><br></p>'}},mounted() {document.execCommand('defaultParagraphSeparator', false, 'p')},methods: {onInput(event) {const turndown = new TurndownService({emDelimiter: '_',linkStyle: 'inlined',headingStyle: 'atx'})this.$emit('input', turndown.turndown(event.target.innerHTML))},applyBold() {document.execCommand('bold')},applyItalic() {document.execCommand('italic')},applyHeading() {document.execCommand('formatBlock', false, '<h1>')},applyUl() {document.execCommand('insertUnorderedList')},applyOl() {document.execCommand('insertOrderedList')},undo() {document.execCommand('undo')},redo() {document.execCommand('redo')}}
}
</script>

结论

只需要87行代码便实现了一个简易的富文本编辑器。虽然功能还是太简单,但是最起码我们知道了实现一个富文本编辑器后面的原理。后面需要增加功能就不是什么难事了。

分享硬核的编程知识,关注“太空编程”公众号

如何用Vue实现简易的富文本编辑器,并支持Markdown语法相关推荐

  1. 安卓文本编辑器php cpp,用安卓原生控件封装一个简易的富文本编辑器

    最近接到项目需求:移动端原生写一个富文本编辑器.        ( ⊙ o ⊙ )从没遇到过富文本要用原生写的,然后就查阅各种资料.然后结合自己的思路:其实安卓的富文本编辑器就是一个 "容器 ...

  2. Vue中使用vue-quil-editor富文本编辑器+el-upload实现带图片上传到SpringBoot后台接口

    场景 系统中经常会用到富文本编辑器,比如新增通知和公告功能,并且需要添加上传图片. vue-quill-editor官网: https://www.npmjs.com/package/vue-quil ...

  3. ueditor html中使用方法,vue集成百度UEditor富文本编辑器使用教程

    在前端开发的项目中,难免会遇到需要在页面上集成一个富文本编辑器.那么,如果你有这个需求,希望可以帮助到你. vue是前端开发者所追捧的框架,简单易上手,但是基于vue的富文本编辑器大多数太过于精简.于 ...

  4. vue问题四:富文本编辑器上传图片

    vue使用富文本编辑器上传图片: 我是用的是wangEditor 富文本编辑器 demo:http://www.wangeditor.com/ 1).安装依赖:npm install wangedit ...

  5. 基于 Vue 的移动端富文本编辑器 vue-quill-editor 实战

    优秀的富文本编辑器有很多,比如:UEditor,wangEditor 等,但并不是每个都能在移动端有很好的表现. 我们暂且不讨论移动端是否真的需要富文本,既然有这需求,就把它实现出来. 失败的尝试 正 ...

  6. Vue 自定义富文本编辑器 tinymce 支持导入 word 模板

    自定义富文本编辑器分为前端项目和后端项目两个部分,首先先说一下前端项目 前端 前端项目地址: https://github.com/haoxiaoyong1014/editor-ui 编辑器名称: t ...

  7. vue中使用wangeditor富文本编辑器(含图片上传和回显)

    最近在写vue的项目中,遇到一个需求,点击编辑,显示弹框,在弹框中的富文本编辑器中编辑自定义文本样式,可以上传图片并回显.编辑完成确定后显示在页面上. 首先先写一个editor.vue的页面.(建议单 ...

  8. vue中使用element-tiptap富文本编辑器

    element-tiptap富文本编辑器 npm安装 npm install element-tiptap --save yarn安装 yarn add element-tiptap 全局引入 imp ...

  9. vue项目:集成富文本编辑器 - 百度ueditor(vue-ueditor-wrap)

    一.背景 集成百度ueditor,实现图文编辑 二.项目介绍 vue---nuxt项目 vue项目:ueditor(vue-ueditor-wrap) 三.集成步骤 3.1.下载富文本编辑器 GitH ...

最新文章

  1. vertx核心类之VertxImpl
  2. 怎么导入sklearn包_在导入sklearn包是报错
  3. 13.4 MySQL用户管理;13.5 常用sql语句;13.6 MySQL数据库备份恢复
  4. web.xml文件报红,怎么解决???
  5. 学php要懂js吗,js要怎么学
  6. Linux文件查找命令find用法整理(locate/find)
  7. 55种数据可视化开源工具_8种出色的开源数据可视化工具
  8. Typora for Mac(文本编辑器)
  9. vivado路径最大时钟约束_Vivado时序收敛技术(二) 时序违例的根本原因及解决方法...
  10. 白盒测试用例设计方法
  11. 电阻屏和电容屏的区别
  12. 01-探寻 JavaScript 反爬虫的根本原因
  13. mysql 共享_Mysql局域网共享
  14. 计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...
  15. android开发隐藏图片,用美图看看安卓版教你如何隐藏私人图片(图文)
  16. python scratch unity怎么读_Python如何像scratch一样朗读文字?
  17. Kali2020详细的安装教程
  18. vue项目json格式化显示
  19. 宁夏慢阻肺数字化管理中心与葛兰素史克启动战略合作
  20. 看雪题库REVERSE的马到成功

热门文章

  1. PAT 乙级(Basic Level) 题解汇总(持续更新)(C++)
  2. 飞畅 8口RS-485集线器产品性能参数介绍
  3. 视频数据复用光端机故障排除方法
  4. 【渝粤教育】电大中专微生物与寄生虫基础作业 题库
  5. 【渝粤题库】陕西师范大学202881 电子商务概论
  6. 【渝粤题库】陕西师范大学163202 管理学原理 作业(高起本 专升本)
  7. EPS(Evolved Packet System,演进的分组系统)
  8. python关于文件的编程题_《Python编程》源代码文件
  9. mybatis delete返回值_面试:谈谈你对MyBatis执行过程之SQL执行过程理解
  10. c语言7.5return的值是,这个真心搞不懂了。求助