I. Introduction
Presumably, when everyone sees this title, several questions will arise in their minds:
- What is a rich text editor?
- What is the relationship between rich text editors and game characters?
- Why upgrade ing?
What is a rich text editor -Rich text editor integrates a series of editing functions such as formatting, media embedding, social interaction, etc., WYSIWYG provides users with multiple display effects. For example, rich text editors are used in forums, communities, comments, etc.
The relationship between text editors and game characters have a lot in common. In order to make the introduction of rich text editors more substituting, this article will use the analogy of game characters to explain. As for the similarities, we will introduce them one by one later.
Why is upgrading ——"Upgrading" stands for continuous progress. The purpose of this article is to focus on the common problems of rich text editors, and provide some ideas for solutions. The rich text editor has been in continuous development, and the exploration of common problems has never stopped.
This article is mainly divided into five parts:
- Preface
- Learn about the rich text editor
- Rich text editor selection guide
- How to extend the rich text editor
- to sum up
This article uses the analogy of game characters, and hopes that developers who have less contact with the rich text editor can gain a deeper understanding of the rich text editor. Today, we will discuss the common problems encountered in the selection and expansion of the rich text editor.
Second, understand the rich text editor
Usually, before choosing a new game, we will choose to go to the official website and forum to learn about the game information and filter out effective information to assist us in choosing a suitable role.
When a developer receives a demand for a rich text editor, he will not choose one of them casually, but will make technical selections based on huge data. The content of this section is the preparatory work for the subsequent selection.
2.1 Character style-rich text editor form
Before the game is launched, the characters will be equipped with different styles by default, and the style often determines our initial impression of the character.
The rich text editor also has several commonly used initial forms, classic mode, document mode, and inline mode, as shown in the following figure:
From the comparison of the above figure, it can be seen that the essential part of the rich text editor is the content editing area. The status bar is used to record related data during editing and can be hidden. The toolbar can adjust the display position, timing and even switch to behind-the-scenes control (triggered by shortcut keys, etc.).
On the contrary, we can get such a message: through different combinations of toolbar, content area, status bar, and menu bar, the rich text editor can be given different display forms.
2.2 Growth stage-development history of rich text editor
The characters in the game are all characters. There will always be some 160e422a793657 bottleneck periods during the growth process. After the so-called bottleneck period, the abilities of the characters will change obviously.
Throughout the development process, the rich text editor has encountered some difficulties. It is precisely because of these difficulties that the development process can be divided into L0, L1, L2 and L3 stages.
L0->L1
L0, the original rich text editor, relies on the browser's own execCommand, and only provides a limited number of commands to achieve the simplest functions. With the increasingly rich requirements for styles, the rich text editor at this time cannot meet the demand, and the editor of the L1 stage came into being. L1's rich text editor uses customize the execCommand program, which can achieve richer rich text functions.
L1->L2
The rich text editors of L0 and L1 still modify HTML through execCommand. In different browsers, the HTML structure of rich text with the same appearance may be quite different.
For example, bold, the HTML may be bold , bold , or bold and so on. In order to solve the problem that data and views cannot be one-to-one correspondence, the concept of custom data model is proposed.
custom data model is a data structure extracted by the rich text editor on the basis of the rich text HTML-DOM tree. The same data structure can ensure that the rendered HTML is also the same. The custom command directly controls the data model, and ultimately ensures the consistency of the rendered HTML document.
For the same HTML, different rich text editors ultimately render different data models. Taking Hello EditorName as an example, the data models of Quill, ProseMirror, Draft, and Slate are compared as follows:
The rich text editor in the L2 stage solves the problem of dirty data and complex functions in the rich text by extracting the data model. Driven by data, it can better meet the needs of customized functions, cross-terminal analysis, online collaboration, etc.
L2->L3
The editor up to the L2 stage can satisfy most of the usage scenarios. Then why did L3 be developed later?
This is because the rich text editors of L0-L2 are based on the contentEditable of the browser. When modifying the data model, it is often necessary to intercept user operations. It is difficult to control user behavior interception, coupled with compatibility issues of different browsers, it is easy to have bugs.
In order to solve the uncontrollable problem of contentEditable editing, the editor represented by Google Docs entered the L3 stage self-developed typesetting engine"
The self-developed typesetting engine completely abandoned the contentEditable, and achieved the editing effect similar to the browser by controlling the cursor position, selection drawing, typesetting, monitoring input and other behaviors. "Self-research" undoubtedly has higher scalability. However, corresponding to this, its development is difficult, costly, and many hidden problems. There is still a certain gap between the overall experience and performance and native browser rendering. The editor at this stage has a way to go.
ps: There are a thousand Hamlets in a thousand people's eyes。
The following division of growth stages is based only on the author's own views.
Looking back at the development process of the rich text editor, it is not difficult to find that the structure of the rich text editor cannot be separated from the three modules of model, view, and controller. As shown below:
Just as the bottleneck period broke through 160e422a79395b by the game character, the custom data model; the change from L2 to L3 is: the new definition of the typesetting engine.
Three, rich text editor selection guide
After we have learned about the game background and character information through various channels, the next step is to log in to the game to create game characters. At this time, the trouble that novices often encounter is undoubtedly: how to choose the most suitable game character for them.
Similarly, for friends who are new to rich text editors, the question often asked is: Which rich text editor should I choose?
First of all, you can choose the rich text editor of the corresponding stage according to your business needs:
- The business itself is based on rich text editors, or there is a need for collaborative editing. —— Choose L2, L3 editor extension, or self-developed editor. You can refer to Youdaoyun's notes and Yuque's solutions here. See the end of the article for reference links.
- Business requirements are frequent iterations, and interaction design requirements are high. —— It is recommended to choose L2 editor.
- The business is relatively stable and not demanding. ——L1, L2 are optional.
- If the business scenario is more complex, it is difficult to judge the future business scenario. ——It is recommended to choose L2 editor.
Secondly, based on the selected stage, according to the project architecture (Vue, React, Augular, etc.), as well as the characteristics of the rich text editor itself, you can choose the appropriate editor. It can be considered from the following aspects:
- Open source
- Community ecology
- Interaction details
- Extended support
- Customized cost
The above is the selection routine I sorted out. Such as CKEditor, TinyMCE, Quill, etc. are all well-known, you may wish to consider these editors when choosing a model:
Fourth, how to extend the rich text editor
Choosing the right character is just the beginning of the game . In the course of the game, the skill tree of the game character needs to be constantly adjusted to develop its potential to the limit.
With the continuous development of the business, higher requirements will be put forward for the rich text editor. In this regard, developers are often troubled by the following issues:
1. How to quickly expand the rich text function?
2. How to quickly change the editor?
For the above two issues, the following will from two aspects: 160e422a793cc3 capacity expansion and theme transformation
4.1 Capacity expansion
The content in this section will not focus on how to expand a certain rich text editor, but will share some general processing ideas for the different expansion methods mentioned above.
4.1.1 Toolbar extension
Just like in a game character, through different assembly schemes of props, adjust the final combat power data. Toolbar extension is to meet the final business needs through the combination and transformation of different functions in the toolbar.
The common toolbar is composed of several function buttons, status button groups, drop-down menus, modal boxes, etc., as shown in the following figure:
Generally, rich text editors have configuration items for managing toolbars, and you can consult official documents as needed. Here we discuss a scenario, the existing function buttons?
Take the "Quill editor font highlighting function" as an example-the color of the function button corresponds to the font color at the cursor position, so as to achieve the effect of binding changes, as shown in the following figure:
So, if the rich text editor introduced in the project does not provide such capabilities, how should we deal with it? Two options are provided here:
1) Control the native UI style of the function buttons.
The following figure shows the font highlighting function of Tiny as an example. The button is an svg structure, which can be achieved by controlling strokeColor/fillColor. At this time, you only need to add the OnSelectionChange monitoring of the cursor position change in the editor, get the font highlight color of the cursor position, and reset the button UI.
2) The SVG icon replaces the current button.
This solution can be used when the function buttons are presented in the form of pictures and it is difficult to control UI changes. Replace the picture icon with the SVG icon, and achieve the same effect by changing the strokeColor/fillColor of the svg-path.
Summary: If the project is to introduce a rich text editor for the first time, here might as well refer to 4.2 theme transformation program two .
4.1.2 Menu bar expansion
" menu bar expansion " is similar to adding some auxiliary skills to the equipment of the game character. These new abilities depend on the equipment, and the abilities of each equipment are also different.
The menu bar mentioned in this section refers specifically to the inline menu bar inside the editor. Such as picture toolbar, table toolbar, right-click menu bar, etc. As shown below:
For the menu bar, the most common requirement is: Add a new menu bar to the existing plug-in, how to realize it?
1) The rich text editor provides the ability to associate configuration, directly follow the API document configuration to . Here is an extract of the configuration scheme of part of the menu bar in the Tiny editor, as shown in the following figure:
2) Without the ability to associate configuration, you need to monitor the change of the cursor position at this time. When the cursor changes in the corresponding rich text data area, trigger events/commands control the display of this menu bar.
Regardless of the above scheme, the extended menu bar can be built into the editor, or it can be thrown out of the editor through events and associated in the form of a custom component. I recommend the scheme of using custom menu bar components:
// 伪代码仅作为示例 辅助理解
// 富文本编辑器
<Editor :config="editorConfig"/>
// 自定义菜单栏组件
<ContextToolBarComponent @command="handleCommand"/>
editor.on("selectionChange",(selection)=>{
// 判断选区位置
CheckSelectionDataModel(selection)
// 控制菜单栏展示隐藏,绑定数据实体
ControlContextToolBarComponentShowHide(selectionPosition)
})
// 菜单功能触发
handleCommand(command, _instance){
editor.execCommand(command, _instance)
}
4.1.3 Internal extension of the editor
For the enhancement of the combat power of the game character, the props and equipment belong to the strengthening of the external force, and the character itself also needs to be focused on.
In the section on the development history of the rich text editor, it is concluded that rich text editor cannot be separated from the three modules model, view, and controller. Then, starting from these three modules, the extended solutions are also differentiated.
data model extension
As mentioned in the previous introduction, the key behavior of the L1-L2 phase transition is pull away from the custom data model . The data model of the rich text editor determines the structure of the final rich text rendering. When a preset rich text structure cannot meet expectations, the data model of this rich text needs to be extended. Depending on whether the rich text editor is before or after the L2 stage, the expansion method is also quite different.
以图片数据扩展关联图片备注为例,将
<figure>
<img src=“xxx”/>
</figure>
扩展为
<figure>
<img src=“xxx”/>
<caption>图片备注</caption>
</figure>
1) L2 stage and later rich text editor has the data model abstraction ability, at this time only need to add/edit the defined data object in the data structure, and bind the rendered HTML structure:
// 原数据结构 {type:'image',src:'xxx'}
// 扩展为 {type:'image',src:'xxx',caption:'图片备注'}
// 新增数据对象 caption:'图片备注',绑定HTML结构 `<caption>图片备注</caption>`
2) before L2 phase , rich text abstract data model data is not performed. For this scenario, you can use the html-parse-stringify plug-in to extract the data model by yourself, and then expand the data. Take <p>hello HTML-parse-stringfy ! </p> As an example, it can be transformed into the data structure shown in the figure below:
The html-parse-stringify plug-in can transform HTML_AST into the required data structure. The current html-parse-stringify also has some problems. This article will not spread, and interested students can leave a message for discussion.
view extension
The view should be easier to understand. Characters with the same attribute data, equipped with different skins or skill special effects, have different presentation effects during the battle. The same rich text data source can be expanded through different views to show different visual effects.
1) does not change the rich text data structure , only differentiates in style settings
Switch between different styles by switching the class attribute bound on the DOM structure:
<blockquote class="pgc-blockquote-abstract">引用内容</blockquote>
<blockquote>引用内容</blockquote>
<blockquote class="pgc-blockquote-quote">引用内容</blockquote>
2) directly changes the data structure of the rich text
The normal link is switched to the card, the data structure is switched from Inline-Block to Block (link-card), and the DOM rendering is switched accordingly. The DOM structure comparison is as follows:
<p><br></p><p><a href="http://www.vivo.com.cn">vivo智能手机官方网站-X60系列丨专业影像旗舰</a></p><p><br></p>
<p><br></p><a href="http://www.vivo.com.cn" data-draft-node="block" data-draft-type="link-card">vivo智能手机官方网站-X60系列丨专业影像旗舰</a><p><br></p>
Controller extension
Controller is a relatively abstract concept. For game characters, it is mainly used to control skill trigger conditions, release timing, trigger conditions, and attribute effects.
Similarly, the controller of the rich text editor is also a general term for the control methods of the data layer and the view layer. The expansion of the controller can be realized in multiple dimensions such as events, commands, and configuration items. Today, let’s briefly talk about the event and can be extended.
1) Expansion of events
event is a bit like an active skill, actively released by the character. The rich text editor will actively throw some events to achieve control inside or outside the editor, such as OnselectionChange, OnInit, and so on. When the newly added function needs to be controlled by the external components inside the editor, and the native event cannot be satisfied, it is often implemented in the form of newly added event monitoring.
The expansion of events is very useful in cross-terminal operations, which will be highlighted in the article on cross-terminal practice.
// 简单举个例子,图片上传失败后往往需要触发重新上传 :
// 若图片通过编辑器上传,失败后点击重新上传是编辑器自带的行为逻辑。
// 但放在客户端控制资源上传的场景下,便需要编辑器通知客户端“某某资源重新请求上传”。
// 这个时候的跨端通信,就需要富文本编辑器抛出事件通知客户端执行操作。
editor.on('appRetryingUploadImage', ({ data }) => {
call('reUploadPic', { picUrl: data.path, fileId: data.id })
})
2) Expansion of the command
command control is the opposite of event control logic. Commands are similar to passive skills. When the external environment reaches a certain condition, it triggers a certain operation of the . The command management of the rich text editor provides the ability to control the internal operations of the editor outside the editor. When the operation is not in the Commod command library, the Command command needs to be extended. Different editors have different ways of writing the extension of Command, but they are always the same-the core of Command is exec and refresh.
以CKEditor与Tiny为例:
CK5
class XXXCommand extends Command{
refresh(){}
execute(){}
}
CK4
editor.addCommand('XXXCommand', {
exec: ()=> {},
refresh: ()=>{}
})
Tiny
editor.addCommand('XXXCommand', () => {});
exec is the callback function for executing commands, which is used to control the execution of related operations of the editor; refresh is the callback function after the command refers to the end of the line, which is often used to control the refresh of the relevant state of the editor after the command is executed;
In addition to events and commands, some editors can also achieve customized operations by extending configuration items.
4.1.4 Add rich text function plug-in
To maximize the value of new skills, it is not only necessary to upgrade the character's attribute data to an appropriate level, but also to flexibly deploy skill sets, configure appropriate props and equipment, and so on.
A new plug-in is added to the rich text editor, which often requires multiple modules to be extended together:
Expand and introduce each module in the above figure below:
Define data model
Through the 4.1.3 Data Model Extension , we can find that the data model is the core of the new rich text function. Only by determining the data layer first can you decide how to control the rendering of the view and how it will ultimately be rendered on the front end.
Defining the data model is mainly divided into three steps:
1. Determine whether the DOM of the data model is Inline type, Block type or switchable;
2. Clarify the access restrictions and editable restrictions of the data model, for example, such rules as saying that hyperlinks cannot be nested in the title;
3. Determine the data model and its data input and data output;
- data input is the content that needs to be configured, taking the picture as an example, the picture URL and the remark copy of the picture are required
- data output is the DOM structure after HTML rendering of the editor
- data model includes: stored HTML string, abstract custom data type (JSON)
An example diagram of input-model-output conversion is shown in the following figure:
custom toolbar button
Toolbar buttons are windows for data control, which can be displayed externally in the toolbar or hidden through shortcut keys. If it is displayed in the toolbar, you need to customize the function buttons of the corresponding state, bind the menu or control operations according to specific needs, please refer to 4.1.1 Toolbar extension .
New event or command
After determining the data core and control window, the next step is to formulate a control strategy. First of all, determine whether the control strategy in the requirement is forward-triggered by the operation of the rich text editor to trigger external feedback, or reverse-triggered by the external operation of the editor, or whether both exist. Then, according to the control strategy, you can choose to expand events, commands, or both. For the specific expansion plan, please refer to 4.1.3 Controller Expansion
associated cursor selection
Through the cursor position, determine the data structure corresponding to the current selection, thereby controlling the switching of special states. How to determine whether you need to associate the cursor selection?
1. Whether the button status of the new function is related to the cursor position. The association can be completed in the step of customizing the toolbar button;
2. Whether the new function needs to be displayed in the associated menu bar. Refer to 4.1.2 Menu Bar Extension processing plan;
3. Whether the new function is related to other rich text functions. Such as mutually exclusive logic-hyperlinks are not allowed to be inserted in the title;
If it is determined that the cursor selection area needs to be associated, the OnSelectionChange monitoring needs to be added in the rich text editor to complete the related processing.
editor.on("selectionChange",(selection)=>{
// 判断选区位置
CheckSelectionDataModel(selection)
// 修改自身及其他按钮状态
ChangeButtonStatus(button)
// 控制菜单显隐
ControlMenuShow(menuBar)
})
Association operation record management (undo, redo)
When performing interactive operations in a rich text editor, some misoperations will inevitably occur. The more complex the interactive scene of the rich text editor, the higher the probability of misoperation. Therefore, general rich text editors will manage operation records to reduce the impact of misoperation.
The processing logic of undo/redo is different in different rich text editors. The similar thing is that the rich text editor will define key behaviors (such as common insertions, deletions, etc.) during the operation and store them in the operation record.
When we associate operation record management in the newly added plug-in function, we only need to reuse the inbound and outbound logic of the key behaviors of other plug-ins.
// 伪代码,仅辅助理解
UndoManage.push(keyOperation)
UndoManage.undo()
UndoManage.redo()
add copy and paste control
"Copy and paste" is considered to be one of the most troublesome problems in the operation of rich text editors. Friends with relevant development experience should have encountered the situation where the content copied from other sources is pasted into the editor, and the view shows abnormal situations. In response to this situation, it is often necessary to filter the data in the clipboard and convert it into data that can be recognized by a rich text editor.
editor.on('paste',(evt)=>{
// 根据光标处对应的数据结构,确定过滤规则
let filterRules = checkSelection()
// filterRulers JSON数据结构对数据对象进行过滤修改
// filterRulers HTML字符串可以使用正则表达式或者编辑器内置的过滤方法
evt.data = filterRulers.exec(evt.data)
})
4.2 Theme transformation
"Theme transformation" should be well understood, that is, changing the skin in the game and quickly switching the style of the game character.
The theme transformation in the rich text editor is actually the replacement of the toolbar, menu bar, and the style of special rich text. There are two usual solutions:
Introduce new theme style files. Replace the new theme style file, or overwrite the old theme style.
Build toolbar components that are separate from the editor itself. Remove the toolbar and menu bar involved in the theme modification from the editor, and create a brand new toolbar component and menu bar component in the project.
If it is to transform an existing project, then the input-output ratio of the new and old theme switching needs to be considered, and the preferred one is selected; if it is a new project and requires high theme style details, option two can be adopted.
// 伪代码 仅辅助理解
<!-- 自定义工具栏 -->
<CustomToolbarComponent>
<ButtonBold @click="execCommondBold"/>
<ButtonUnderline @click="execCommondUnderline"/>
<ButtonHead @click="execCommondHead"/>
</CustomToolbarComponent>
<!-- 富文本编辑器编辑区域 -->
<EditorContainer></EditorContainer>
<script>
// 执行富文本编辑器的Commond
execCommondBold:()=>{
editor.execCommond('bold')
}
execCommondUnderline:()=>{
editor.execCommond('underline')
}
execCommondHead:()=>{
editor.execCommond('head')
}
</script>
<style>
// 自定义主题样式
button-bold{}
button-underline{}
button-head{}
</style>
Compared with the first option:
- Advantages : Migrate the control of the toolbar from a third-party editor to the project. The controllability and scalability can be maximized; the adaptability to cross-end services is higher, and each end is only A set of control plan is needed, and each functional component can be customized by channel;
- Disadvantages : Need to transfer the command/event, status binding and other control schemes bound to the buttons in the toolbar to the new component, which will take up a certain development cost.
Summary : There are more than the above schemes for function expansion and theme transformation. There are also other compromise schemes. You only need to choose the appropriate scheme according to the business scenario. There is a saying: "The best is not necessarily suitable, the suitable is the best" .
At this point, the content of this article is coming to an end. I hope everyone can see here and get some answers to the following questions:
1. Based on current business needs, which rich text editor should I choose?
2. As the business expands, how to expand the rich text function?
3. How to change the design quickly?
Five, summary
Just like in the game world, you have to fight monsters to upgrade. At the same time in the process, you will also accumulate more skills to lay a solid foundation for the subsequent leapfrog fighting monsters. During the development of the rich text editor, we will indeed encounter many difficult problems and complex requirements, which cost us a lot of time and energy. In time after time of training, we will all gain something and grow.
This article shares some of my thoughts on common issues during the development of the rich text editor. I hope to bring some help to the friends who are about to participate in the development of the rich text editor or those who are developing the rich text editor. .
Later, I will share with you some experience of rich text editors in cross-terminal solutions. If you are interested, you can continue to pay attention.
reference
- Youdao Cloud Note New Edition Editor Architecture Design (
- Youdao Cloud Note New Edition Editor Architecture Design (Part 2)
- The technological evolution of the rich text editor
- open source rich text editor technology (2020 1024)
- Talk about the plight of the rich text editor from the popular editor architecture
- Quill Editor
- CKEditor
- TinyMCE
Author: vivo Internet front-end team-Tian Yuhan
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。