富文本编辑器开发系列-1-基础概念-程序员宅基地

技术标签: 前端编辑器探究  前端  富文本编辑器  基础  

前言

富文本编辑器是前端开发中常见的功能,一般情况下,我们可以用成熟的开源富文本编辑器,比如比较老牌的 ueditor, ckeditor , 或者近几年兴起的 draft.js 等。

但是,总会有二般情况:

  • 实际应用需求超出了这些开源编辑器提供的标准功能;
  • 实际应用需求很少,使用这些开源编辑器会过于复杂和臃肿;

这个时候,我们就面临着两种选择:

  1. 对这些开源编辑器进行二次开发,以适应应用需求;
  2. 自己从头撸一款富文本编辑器,自己掌控一切;

这两种选择,都意味着我们要对富文本编辑器的底层技术有所了解,甚至如果要自己撸一款富文本编辑器的话,还要非常精通这些技术,所以从本文开始,就将用比较通俗易懂的方式(就是好多好多动态图和逻辑图),对开发富文本编辑器涉及到的基础技术进行讲解。以帮助朋友们飞升(升职加薪走一波)。

系列文章快速阅读:
富文本编辑器开发系列-1-基础概念
富文本编辑器开发系列2-document.execCommand 的API
富文本编辑器开发系列3-selection
富文本编辑器开发系列4——Range对象
富文本编辑器开发系列5——浏览器Selection API探究
富文本编辑器开发系列6——Range API 探究
富文本编辑器开发系列7——textRange对象详解
富文本编辑器开发系列8——常用DOM API
原生API编写简单富文本编辑器001
原生API编写简单富文本编辑器002
原生API编写简单富文本编辑器003
原生API编写简单富文本编辑器004
原生API编写简单富文本编辑器005

富文本编辑器的基本发展史

整体来说,富文本编辑器经历了三个阶段的发展。

1.0 时代 —— 原始时代,contenteditable 大法好

在那个前端工程师还叫做网页设计师(俗称切图仔)的刀耕火种的年代,各种BBS留言板的出现,产生了对前端更丰富的文本编辑的需求,传统的textarea已经远远不能胜任,所以出现了第一代的富文本编辑器。

那时候的编辑器存活到现在的已经没有了,但他们是开拓者,这些前辈开发者利用浏览器DOM提供的 contenteditable 属性和 document.execCommand 方法,开发出了第一代的轻量级的富文本编辑器。虽然其功能及其简单,也只是单纯利用了web浏览器提供的原生API,但是为后面2.0时代的富文本编辑器打下了基础。

2.0 时代 —— 现代化,视图与模型分离

进入2.0时代,由于浏览器document.execCommand 有着各种各样的问题,大神们决定自己实现execCommand 方法,自己掌控内容的变化与格式,由此产生了一大批优秀的更加现代化的富文本编辑器,如ueditorckeditor 早期版本等。

后来,进入21世纪后,视图与模型分离的思想逐渐征服了前端的大神们,于是又出现了改进版的将视图与数据模型进行分离管理的现代化编辑器,如draft.js , ckeditor 后期版本等。

image-20200827101736796

3.0 时代 —— 后现代, 抛弃 contenteditable

由于急于contenteditable的编辑器,其输入完全是由用户掌控,而非由开发者掌控,所以就会出现无穷种不同的dom结构,造成各种不可控不可预知的行为后果,这对于追求可控严谨的前端工程师们来说简直是噩梦。所以出现了3.0时代的富文本编辑器。

开发者彻底摒弃了contenteditable属性,而是完全使用普通布局容器加js对DOM事件的监听实现,完全将富文本编辑器的输入到渲染的整个流程都在自己的掌控之中。比如 google docs, office online, icloud pages, wps在线编辑等。

image-20200827102744432

因为第三代编辑器实现起来动辄需要几十万到几百万行代码,需要一个非常庞大和专业的团队去开发和维护,也只有文本编辑的巨头能搞得起,所以,当前应用最广的依旧是第二代浏览器。

基础概念

编辑区

在一个完整应用界面中,富文本编辑器通常都是一个表单的一部分,而在编辑器中,编辑区是除去工具条(各种功能按钮所在区域)和状态栏(显示字数等额外信息)以外的,允许用户输入内容的区域。

但是编辑区并不是富文本编辑器独有的概念,事实上,只要是设置了contenteditable 属性的DOM元素包裹的内容区,都允许用户输入内容和对其中的内容进行修改,那这块内容区就是可编辑区,而富文本编辑器只是继承了这种特性和概念。

image-20200827103932904

选区

选区是指当一个编辑区获得焦点时,用户选择的文本范围或插入符号的当前位置。 现代浏览器通常一个编辑区都只有一个选区,只要火狐浏览器可以在一个编辑器内通过按住键盘alt 键产生多个选区。一个选区可以包含多个DOM元素,即它是可以跨节点的。

image-20200827105347754

拖蓝

拖蓝,表示一个包含节点与文本节点的一部分的文档片段。通常情况下,选区与拖蓝所包含的DOM元素部分是相同的,它们的不同在于其本质,选区偏重于强调范围和位置,而拖蓝强调的则是包含的DOM内容。从它的表现形式就可以知道它为什么为叫做拖蓝(拖动后产生的蓝色区域)。

当然,拖蓝是中文意译法,其英文是range(范围)

image-20200827105702294

光标

光标是特殊的拖蓝,可以认为光标就是移动拖蓝的某个端点到另一个端点的位置,两个端点重合时所在的区域或位置。

基本API

contenteditable

该属性用在DOM元素上,它用来表明元素是否可编辑,如:

<div contenteditable="true"></div>

上面的HTML 语句表明这个div包裹的区域是允许用户进行编辑的。

这个属性有三个可选值:

  • "true" 表明该元素可编辑。
  • "false" 表明该元素不可编辑。
  • "inherit" 表明该元素继承了其父元素的可编辑状态

document.execCommand()

这是HTML文档对象的一个方法,该方法可以被用来操纵可编辑内容区域的元素。

语法

bool = document.execCommand(name, isShowDefaultUI, argument);

参数说明

  • name , 字符串,命令的名称,可用命令见下文表格
  • isShowDefaultUI布尔值,是否展示用户界面,一般为 false, 并且Mozilla 没有实现
  • augument 额外参数,某些命令需要传入额外的参数

具体可阅读 document.execCommand 的API

selection && range

seleectionrange 都是Web API的一部分,同时他们也是实现在开发富文本编辑器中最常用到的API.

对于它们的具体研究,请参阅:

DOM

在实现富文本编辑器的过程中,需要大量的DOM操作,这就要求我们要对DOM的各种API非常熟悉,才能运用正确的API 准确实现预期的功能。

当然,DOM API 非常之多而且很庞杂,很多都是富文本编辑器开发中用不到的,基于此考虑,我单独介绍了开发富文本编辑器常用的DOM API, 请参阅:

富文本编辑器开发系列——常用DOM API

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hjb2722404/article/details/110953976

智能推荐

windows 加 switchyomega + burp 抓https包-程序员宅基地

文章浏览阅读4.6k次。很简单,下载证书后导入到受信任根目录证书下载,直接在代理状态浏览器访问burp点击CA就可以下载了 设置该证书全部信任,,switchyomega 设置如下即可 就可以抓https的包了 ...

用C语言写循环赛日程表,循环赛的方法与编排-程序员宅基地

文章浏览阅读1k次。一、循环赛的种类与特点(一)循环赛的种类循环赛又称循环法。是指参赛队(或个人,下同)之间,都要互相轮流比赛,最后按照各参赛队在全部比赛中的胜负场数、得分多少排定名次的比赛方法。它在对抗性项目比赛中经常被采用。循环赛包括单循环、双循环或分组循环三种。单循环是所有参赛队(人)相互轮赛一次;双循环是所有参赛队(人)相互轮赛二次;分组循环是参赛队(人)较多时,采用种子法,把强队(人)分散在各组,先进行小组..._c语言循环赛互打一场比赛 甲队两胜

springboot项目访问html页面,发现端口不一致&继承WebMvcConfigurationSupport类会导致自动配置失效_springboot项目前端端口号不同怎么办-程序员宅基地

文章浏览阅读1.6k次,点赞4次,收藏6次。最后的解决方法“在config--WebMvcConfig中不要继承WebMvcConfigurationSupport,而是实现WebMvcConfigurer接口”,且不要在idea中直接点击浏览器图标打开对应的html页面,要自己在浏览器输入url。在本次debug过程中,更加清楚地明白了,springboot项目启动过程中,只扫描引导类同包或子包下的程序,而在resources目录下的静态资源文件(没放到),需要被映射,才能被扫描到。_springboot项目前端端口号不同怎么办

k8s.配置管理.configmap&secret_configmap @value-程序员宅基地

文章浏览阅读80次。configmap 和secret 都需要提前创建configmap和secret都可以为pod提供挂载和变量的方式变量的方式有envfrom全部变量和valuefrom单个变量的引用configmap和secret 需要和引用的pod或者资源对象在同一个ns下。_configmap @value

System.TypeInitializationException: 'The type initializer for 'MySql.Data.MySqlClient.Replication.Re...-程序员宅基地

文章浏览阅读2.2k次。下午在调试的时候报错数据库连接就报错我就很纳闷后面用原来的代码写发现还是报错System.TypeInitializationException:'The type initializer for 'MySql.Data.MySqlClient.Replication.ReplicationManager' threw an exception.'应该是出在Mysql包上的问题..._system.typeinitializationexception:““mysql.data.mysqlclient.mysqlpoolmanag

树莓派上部署jeecg-boot快速开发平台_jeecgboot linux部署-程序员宅基地

文章浏览阅读249次。系统安装Ubuntu Server(可百度)更换软件源打开位置cd /etc/apt/编辑sources.listsudo nano sources.list使用清华的软件源镜像deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal main restricted universe multiversedeb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-updates main restricted univ_jeecgboot linux部署

随便推点

快给你的Vue项目添加一个编辑图片组件吧_vue-image-editor-程序员宅基地

文章浏览阅读8.2k次,点赞20次,收藏59次。快给你的Vue项目添加一个编辑图片组件吧给大家推荐一款功能极其强大的图片编辑插件 tui.image-editor快速体验首选在你的前端项目中安装:npm i tui-image-editor// oryarn add tui-image-editor现在你就去新建一个.vue文件,复制进去下面这段代码:<template> <div id="tui-image-editor"></div></template><scr_vue-image-editor

Flutter混合开发-Null check operator used on a null value_flutter null check operator used on a null value-程序员宅基地

文章浏览阅读4.8k次。标题Flutter与Android混编在Android与Flutter混编中导入flutter的GetX框架时,配置getPages参数出错,在编译时不报错,但是运行之后,debug模式下出现红底白色的错误,错误显示为 Null check operator used on a null value,看一眼懵了,本地开发版本使用的是flutter2,配置的Getx库也确实在很早的版本中就支持了Null safety ,且配置的getPages为数组并且可为空,按照常理怎么也不可能出现这个错误!尝试的方案_flutter null check operator used on a null value

查看WIN10 SDK的版本_win10 sdk 版本好哪里查-程序员宅基地

文章浏览阅读4.4k次。查看WIN10 SDK的版本_win10 sdk 版本好哪里查

MFC C++改变控件字体大小颜色的方法_cfont设置字体大小-程序员宅基地

文章浏览阅读1.4k次。MFC C++改变控件字体大小颜色的方法_cfont设置字体大小

requests(网络请求库神器 )库快速上手_requests 在线请求工具-程序员宅基地

文章浏览阅读202次。关于requests(网络请求库神器 )库快速上手urllib、urllib2、urllib3、httplib、httplib2 都是和 HTTP 相关的 Python 模块,看名字就觉得很反人类,更糟糕的是这些模块在 Python2 与 Python3 中有很大的差异,如果业务代码要同时兼容 2 和 3,写起来会让人崩溃。好在,还有一个非常惊艳的 HTTP 库叫 requests,它是 ..._requests 在线请求工具

springboot使用EntityManager执行自定义SQL_springboot 执行自定义sql-程序员宅基地

文章浏览阅读2.9k次。1.在代码中注入 EntityManager import javax.persistence.EntityManager;@AutowiredEntityManager entityManager; 2.在方法中具体使用EntityManager public List<DefColumn> findAllColumns(String table) { Query query = entityManager.createNativeQue._springboot 执行自定义sql