This was originally a rich text editor written for VM-Manager, but later I thought it was more convenient to maintain it independently, so I separated it and put it into NPM. Everyone can write because this component is really simple to implement, doesn’t require a lot of Js proficiency, and is basically a binding to the document.execcommand () directive. I will share the process with you here
IO/vM-editor /
Source address github.com/luosijie/vm…
The installation
npm install --save vm-editorCopy the code
use
The //upload binding event passes compiled HTML characters to the parent component < vmeditor@upload ="showHtml"></VmEditor>
<script>
import VmEditor from 'vm-editor'
export default {
...
methods: {
showHtml: function(data){
console.log(data)
}
}
}
</script>Copy the code
To prepare
Since it is a Vue component, it is necessary to know how to write such a component:
- Vue single file component development
- ExecCommand instruction
Component structure
The component is mainly composed of a menu part and content area 2, in which the menu area is composed of various instruction buttons, and some instruction buttons have drop-down options
Command button
The command button is a loader for execConmand and needs to do the following
- Gray across the background
- Display button icon
- Part of the buttons need to achieve click to expand the drop-down menu
<template>
<button class="vm-editor-button" :class="{ active: slot }"> // Display button icon <img: SRC ="require('.. /assets/iconimg/' + icon + '.png')" height="16" width="16" alt="" @click="showSlot"> <! -- <i :class="icon" @click="showSlot"></ I > --> // Some buttons need to be clicked to expand the drop-down menu <slot V-if ="slot"></slot> </button> </template> <style> ... Button. Vm-editor -button:hover{background-color:#eee;}... </style>export default {
name: 'VmEditorButton',
props: {
icon: {
type: String,
default: 'heading'
}
},
data: function () {
return {
slot: false
}
},
methods: {
showSlot () {
this.slot === false ? this.slot = true : this.slot = false
}
}
}
</script>Copy the code
The menu area
- Bind the execCommand directive to the button
- Click upload button to compile HTML
<template>
<div class="vm-editor-menu"> // Introduces the button assembly, wrapped by the **click event ** bindingexecThe Command method implements style changes <VmEditorButton icon="paragraph" @click.native="execCommand('formatBlock', '<p>')">
</VmEditorButton>
<VmEditorButton icon="heading"> <VmEditorDropdown> // This is the part of the button that requires the dropdown menu function <ul class="vm-editor-ul">
<li @click="execCommand('formatBlock', '<h1>')">
<h1>H1</h1>
</li>
<li @click="execCommand('formatBlock', '<h2>')">
<h2>H2</h2>
</li>
<li @click="execCommand('formatBlock', '<h3>')">
<h3>H3</h3>
</li>
<li @click="execCommand('formatBlock', '<h4>')">
<h4>H4</h4>
</li>
<li @click="execCommand('formatBlock', '<h5>')"> <h5> h5 </h5> </li> </ul> </VmEditorButton> <slot></slot> </div> </template> <style> ... </style> <script> ...export default {
name: 'VmEditorMenu', components: { VmEditorButton, VmEditorDropdown, VmEditorAddlink, VmEditorAddimage, VmEditorFontcolor }, methods: {// Encapsulate the document.execCommand directiveexecCommand: function (commandName, valueArgument) {
// let body = document.querySelector('.body');
if(! valueArgument) { valueArgument = null } document.execCommand('styleWithCSS', null, true)
document.execCommand(commandName, false, valueArgument)}, // Insert image functionsetImage: function (evt) {
let reader = new FileReader()
let file = evt.target.files[0]
reader.readAsDataURL(file)
reader.onload = function (evt) {
let base64Image = evt.target.result
document.execCommand('insertImage'.false, base64Image)
}
}
}
}
</script>Copy the code
The main components
The menu component
The content area
In addition to the implementation of HTML export function
<div class="vm-editor">
<VmEditorMenu>
<div class="global-control"<VmEditorButton icon= <VmEditorButton icon="upload" @click.native="uploadHtml"></VmEditorButton> </div> </VmEditorMenu> // Content area just set **contenteditable="true"<div class= <div class= <div class="content" contenteditable="true" v-html="html">
</div>
</div>
<style>
...
</style>
<script>
name: 'VmEditor',
components: {
VmEditorMenu,
VmEditorButton
},
data: function () {
return {
html: 'Please Enter ... '}}, methods: {export HTML data // current content area style is **CSS style **, export to ** inline ** uploadHtml:function() {// Get the CSS style of each modulelet style = {
ul: `
margin: 10px 20px;
list-style-type: square;
padding: 0;
`,
ol: `
margin: 10px 20px;
list-style-type: decimal;
padding: 0;
`,
li: `
display: list-item;
padding: 0;
`,
hr: `
margin: 15px 0;
border-top: 1px solid #eeeff1;
`,
pre: `
display: block;
margin: 10px 0;
padding: 8px;
border-radius: 4px;
background-color: #f2f2f2;
color: # 656565;
font-size: 14px;
`,
blockquote: `
display: block;
border-left: 4px solid #ddd;
margin: 15px 0;
padding: 0 15px;
`,
img: `
margin: 20px 0;
`,
a: `
color: #41b883;`}let html = document.getElementsByClassName('content') [0]let htmlContainerParent = document.createElement('div')
let htmlContainer = document.createElement('div')
letTagNames = object.keys (style) // Iterate over the HTML node and insert the corresponding inline stylefor (let i = 0; i < tagNames.length; i++) {
let _tagNames = html.getElementsByTagName(tagNames[i])
if (_tagNames.length > 0) {
for (letj = 0; j < _tagNames.length; j++) { _tagNames[j].style = style[tagNames[i]] } } } htmlContainer.style = ` text-align: left; padding: 15px; font-size: 16px; ` htmlContainer. InnerHTML = HTML. InnerHTML htmlContainerParent. The appendChild (htmlContainer) / / registered upload * * * * this custom events.$emit('upload', htmlContainerParent.innerHTML)
}
}
}
</script>Copy the code
Other components
The other components are mostly push-down menus, and because each is different, they have to stand alone
- Vm-editor-addimage: Inserts the image
- Vm-editor-addlink: Inserts links
- Vm-editor-fontcolor: Modify the color
Deficiency in
Because of the short development time of the rich text editor, there was no serious research into the source code of such good plug-ins and no in-depth research into the needs of the rich text editor. I just referenced the implementation and UI style of some of the same editors, such as Simditor, and implemented the functionality briefly.
So there’s definitely a lot of room for improvement, some of the obvious ones are:
- Browser compatibility
- Table function implementation
Anyway, just for your learning purposes, right
The original address
That’s it. Welcome star