合肥市建设工程市场价格信息网站,苏州家政保洁公司哪家好,无锡房产网,产品线下推广方式都有哪些前端开发经常会用到富文本编辑器#xff0c;比如CKEditor#xff0c;动不动一个库几十M的代码量#xff0c;其中涉及许多你可能用不到的功能特性和相关设置#xff0c;CKEditor最新版本的代码仓库就有接近2000个JS文件#xff0c;300,000行代码。
可是如果你只需要一个简…前端开发经常会用到富文本编辑器比如CKEditor动不动一个库几十M的代码量其中涉及许多你可能用不到的功能特性和相关设置CKEditor最新版本的代码仓库就有接近2000个JS文件300,000行代码。
可是如果你只需要一个简易版的编辑器真的值得引入这么一个庞大的库吗
今天我们从实现一个简易版的编辑器带大家了解一下其背后涉及到的原理。
开始
这个编辑器将要使用到markdown一个简洁语法并且自带样式的语言而且远比纯HTML的输入输出要安全得多。
首先我们需要一些依赖包。 ts-stack/markdown 和 turndownts-stack/markdown是用来将markdown语法转化为HTML代码显示用的而turndown是将HTML代码转化为markdown语言。
接下来创建一个基础的Vue组件命名为WysiwygEditor.vue在组件中添加一个div元素并且将它的contenteditable属性设置为true然后添加一些Tailwind样式去美化一下。
!-- WysiwygEditor.vue --
templatedivdivinputonInputv-htmlinnerValuecontenteditabletrueclasswysiwyg-output outline-none border-2 p-4 rounded-lg border-gray-300 focus:border-green-300//div
/templatescript
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-modelsomeText /!-- ... --
/template
!-- ... --看起来像这样
现在这个div元素的样式看起来像textarea 标签的效果了。
让文本变为富文本
在编辑器的上面会有一些带有bolditalicunderlinedheadingslists等文本的编辑按钮。并且上面会有对应功能的图标。可以通过安装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 classflex flex-wrapbutton clickapplyBold classbuttonfont-awesome-icon :icon[fas, bold] //buttonbutton clickapplyItalic classbuttonfont-awesome-icon :icon[fas, italic] //buttonbutton clickapplyHeading classbuttonfont-awesome-icon :icon[fas, heading] //buttonbutton clickapplyUl classbuttonfont-awesome-icon :icon[fas, list-ul] //buttonbutton clickapplyOl classbuttonfont-awesome-icon :icon[fas, list-ol] //buttonbutton clickundo classbuttonfont-awesome-icon :icon[fas, undo] //buttonbutton clickredo classbuttonfont-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 || pbr/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/markdownexport default {name: WysiwygEditor,props: [value],data() {return {innerValue: Marked.parse(this.value) || pbr/p}},// ...我们把输入的内容markdown语法转化为HTML代码之后看起就正常了
同时还需要在组件传出本文编辑器数据的时候进行转化这里要用到前面安装的turndown
import TurndownService from turndownexport 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-modelsomeText /pre classp-4 bg-gray-300 mt-12{{ someText }}/pre!-- ... --
/template同步输入输出内容是一致的没有任何问题
看起来一切正常达到了我们想要的效果。下面是全部的代码
templatedivdiv classflex flex-wrapbutton clickapplyBold classbuttonfont-awesome-icon :icon[fas, bold] //buttonbutton clickapplyItalic classbuttonfont-awesome-icon :icon[fas, italic] //buttonbutton clickapplyHeading classbuttonfont-awesome-icon :icon[fas, heading] //buttonbutton clickapplyUl classbuttonfont-awesome-icon :icon[fas, list-ul] //buttonbutton clickapplyOl classbuttonfont-awesome-icon :icon[fas, list-ol] //buttonbutton clickundo classbuttonfont-awesome-icon :icon[fas, undo] //buttonbutton clickredo classbuttonfont-awesome-icon :icon[fas, redo] //button/divdivinputonInputv-htmlinnerValuecontenteditabletrueclasswysiwyg-output outline-none border-2 p-4 rounded-lg border-gray-300 focus:border-green-300//div
/templatescript
import { Marked } from ts-stack/markdown
import TurndownService from turndownexport default {name: WysiwygEditor,props: [value],data() {return {innerValue: Marked.parse(this.value) || pbr/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行代码便实现了一个简易的富文本编辑器。虽然功能还是太简单但是最起码我们知道了实现一个富文本编辑器后面的原理。后面需要增加功能就不是什么难事了。
分享硬核的编程知识关注“太空编程”公众号