Brief introduction
Rich text editor, enabling web
the page, like word
, like, realize editing of the text, usually used in some more text processing system. Now the industry has a lot of mature rich text editor, such as full-function ah TinyMCE , lightweight and efficient wangEditor , Baidu produced UEditor and so on. Many rich text editor, but few think about how to start from scratch, to achieve a rich text editor. This paper briefly from scratch how to implement a simple rich text editor.
Basic use
Common HTML
labels can be input is generally only form, form input plain text, without the content format. Rich text relative to the form, be able to add some custom content styles to input text, such as bold, font color, background .... Rich text, mainly to the HTML tags, such as div
adding a contenteditable
property, possession of the property HTML
label, the label can be in the content, implement custom editing. The simplest rich text editor as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app" style="width: 200px;height: 200px;background-color: antiquewhite;" contenteditable='true'></div>
</body>
</html>
Basic Operations
Rich text similar to Word, there are many options for manipulating text, such as bold text, add background color, paragraph indents, use is imperative, only need to perform document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
, which aCommandName
is the command name , aShowDefaultUI
a Boolean
, whether to show the user interface , generally false
. Mozilla did not materialize. aValueArgument
, Additional parameters , usually null
.
Basic Operations Command
The following are some examples of simple operations rich text commands, some examples are given below using simple
command | value | Explanation |
---|---|---|
backcolor | Color string | Set the background color of the document |
bold | null | The selected text bold |
createlink | URL string | To convert the selected text into a link to the specified URL |
indent | null | Indent text |
copy | null | Copy the selected text to the clipboard |
cut | null | Cut selected text to the clipboard |
inserthorizontalrule | null | Hr insert a character at the insertion element |
Example:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<!-- https://electronjs.org/docs/tutorial/security#csp-meta-tag -->
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<style>
html, body{
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#app{
display: flex;
flex-direction: column;
justify-content: flex-start;
width: calc(100% - 100px);
height: calc(100% - 100px);
padding: 50px;
}
.operator-menu{
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
min-height: 50px;
background-color: beige;
padding: 0 10px;
}
.edit-area{
width: 100%;
min-height: 600px;
background-color: blanchedalmond;
padding: 20px;
}
.operator-menu-item{
padding: 5px 10px;
background-color: cyan;
border-radius: 10px;
cursor: pointer;
margin: 0 5px;
}
</style>
</head>
<body>
<div id="app">
<div class="operator-menu">
<div class="operator-menu-item" data-fun='fontBold'>加粗</div>
<div class="operator-menu-item" data-fun='textIndent'>缩进</div>
<div class="operator-menu-item" data-fun='inserthorizontalrule'>插入分隔符</div>
<div class="operator-menu-item" data-fun='linkUrl'>链接百度</div>
</div>
<div class="edit-area" contenteditable="true"></div>
</div>
<script>
let operationItems = document.querySelector('.operator-menu')
// 事件监听采用mousedown,click事件会导致富文本编辑框失去焦点
operationItems.addEventListener('mousedown', function(e) {
let target = e.target
let funName = target.getAttribute('data-fun')
if (!window[funName]) return
window[funName]()
// 要阻止默认事件,否则富文本编辑框的选中区域会消失
e.preventDefault()
})
function fontBold () {
document.execCommand('bold')
}
function textIndent () {
document.execCommand('indent')
}
function inserthorizontalrule () {
document.execCommand('inserthorizontalrule')
}
function linkUrl () {
document.execCommand('createlink', null, 'www.baidu.com')
}
</script>
</body>
</html>
Text selection and range
Rich text, the text selection range and is a very powerful means of text selection, we can do some custom settings for the selected text. The core is two objects, Selection
and Range
objects. Comparison with the official statement is, Selection
the object is represented by the current position of the text cursor or a range of user-selected , Range
the object represents a portion of a document fragment comprising nodes and text nodes . In simple terms, Selection
refers to the page, we all areas of the mouse to select, Range
refer to the page in our mouse to select a single region, belonging to many relationship. For example, we want to get the selection object for the current page, you can call var selection = window.getSelection()
, if you want to get to the first text selection information, you can call var rang = selection.getRangeAt(0)
, text selection to get information, the use of range.toString()
.
Text selection and range, is the use of a more classic, rich text format to paste filter . When we copy text into the rich text editor, this will retain the original format, if we are to remove the copy of the default format, leaving only plain text, how does it work?
Bloggers in dealing with this problem, the first thought is, you can listen to paste the event (paste)
, when you paste text, will replace the clipboard contents. It is also inside a pit, clipboard paste operation is not in force. In implementing functional requirements, the initial uses a regular match, remove HTML tags. But since the text format varied, often all kinds of weird characters, more problems, but when copying large text, page performance issues, this is not a good approach, really understand until later text range and selection , only to find this setting, delicious.
Rich text selection processing logic of the general idea is as follows:
- Paste text event listener
- Prevent the default event (to prevent the browser's default copy operation)
- Gets Copy plaintext
- Get the page text selection
- Delete selected text selection
- Create a text node
- Text node into constituencies
- Move focus to the end of the copied text
Sample code is as follows:
let $editArea = document.querySelector('.edit-area')
$editArea.addEventListener('paste', e => {
// 阻止默认的复制事件
e.preventDefault()
let txt = ''
let range = null
// 获取复制的文本
txt = e.clipboardData.getData('text/plain')
// 获取页面文本选区
range = window.getSelection().getRangeAt(0)
// 删除默认选中文本
range.deleteContents()
// 创建一个文本节点,用于替换选区文本
let pasteTxt = document.createTextNode(txt)
// 插入文本节点
range.insertNode(pasteTxt)
// 将焦点移动到复制文本结尾
range.collapse(false)
})