经常在做企业网站的管理系统的时候需要用到富文本编辑器,之前基本上都是直接去 npm 或者 github 上面搜找一些排名考前或者 readme 写的好的库,直接拿来用。万变不离其宗,是时候探索下本质了。

contenteditable

要想实现富文本需要开启“编辑”的能力,系统提供了一个 api:contenteditable 允许我们对内容进行编辑。下面是来自 MDN 的官方解释。

The contenteditable global attribute is an enumerated attribute indicating if the element should be editable by the user. If so, the browser modifies its widget to allow editing. The attribute must take one of the following values: - true or the empty string, which indicates that the element must be editable; - false, which indicates that the element must not be editable. If this attribute is not set, its default value is inherited from its parent element.

contenteditable 的值设置为 true 或者空字符串"" 允许内容被编辑,false 则代表不可被编辑。 它不仅可以作用在 textarea、div、甚至是网页所见的都可以进行编辑。所以利用这点儿你可以做一些 坏事情 ,比如修改教务处网页上的成绩单和绩点分数,修改天气预报的温度走势情况,反手修改某一天的温度为 66度。

document.execCommand

想想看,你在输入框里面输入了一段文字,你点击上面的加粗按钮如何实现?MDN 告诉我们有个 api 可以满足需求。当元素进入编辑模式的时候,document 对象暴露出一个 execCommand 方法去操纵当前的可编辑区域 。看看下方 MDN 给出的解释。

When an HTML document has been switched to designMode, its document object exposes an execCommand method to run commands that manipulate the current editable region, such as form inputs or contentEditable elements. document.execCommand(aCommandName, aShowDefaultUI, aValueArgument) A Boolean that is false if the command is unsupported or disabled.

aCommandName:命令名称。比如加粗、下划线、无序列表、段落、H1等等 aShowDefaultUI:布尔值。是否展示默认的样式,一般为 false aValueArgument:一些命令所需要的额外参数,比如 insertImage 插入图片所需要的图片 url

完整的命令和各个浏览器的支持情况可以查看 MDN。

Selection 和 Range 对象

在执行 document.execCommand 的时候需要知道对谁在什么范围内执行命令。这里有一个选区的概念,也就是 Selection,用来表示用户选择的范围。(说明:用户不选中任何内容,也就是只有一闪一闪的光标的情况也算是一种特殊的选中)。

一个页面包含多个选中区域(Firefox) 支持。所以 Selection 可以看作是 Range 对象的集合。通常情况下我们一般只存在一个选中的区域,所以 document.getSelection().getRangeAt(0) 就可以拿到当前选区的信息。

Range 对象请看下图

选区Range对象1
选区Range对象2

上面说到光标也是一个特殊的选区,当 endOffset 和 startOffset 相等的时候,collapsed 属性就为 true。

通过 document.getSelection().getRangeAt(0) 就可以获取到选区的信息,那么可以将当前选区保存下来,等到需要的时候再拿出来并展示。Selection 对象还有几个开放的方法(addRange、collapse、collapseToEnd、collapseToStart)可以操纵光标(比如插入文字后光标的位置)。

理论联系实际、一切从实际出发

动手做一个简易的富文本编辑器吧。(不想写一个 Vue 或者 React 工程,拿最简单的 html 撸一个吧)

思路: - 新建 html 文件 - 设置2个大的 div,一个展示功能按钮,一个展示编辑区域(编辑区域需要设置允许可编辑) - 样式布局 - 各个功能按钮添加点击事件监听 - 因为点击各个按钮都是执行 document.execCommand,唯一不同的就是命名名称和参数不一样,所以简单封装函数 - 调用封装的函数,传递参数

下面贴出代码

<html>
<head><title>富文本</title><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"><style>.commandZone {margin: 20px;margin-bottom: 0px;background: burlywood;}.editor {border: 1px solid gray;margin: 0px 20px 20px 20px;height: 300px;}.btn {margin: 10px 20px;color: black;font-size: 20px;line-height: 20px;display: inline;}</style>
</head>
<body><div class="commandZone"><button id="paragraphBtn" class="btn">段落</button><select name="hstyle" id="hstyle"><option value="1">h1</option><option value="2">h2</option><option value="3">h3</option><option value="4">h4</option><option value="5">h5</option><option value="h6">h6</option></select><button id="boldBtn" class="btn">加粗</button><button id="undoBtn" class="btn">后退</button><button id="redoBtn" class="btn">前进</button><button id="insertHorizontalRuleBtn" class="btn">水平线</button><button id="insertUnorderedListBtn" class="btn">无序列表</button><button id="createLinkBtn" class="btn">插入链接</button><button id="insertImageBtn" class="btn">插入图片</button></div><div class="editor" contenteditable="true"></div>
</body>
<script>var hStyle = '<h1>';document.getElementById('hstyle').onchange = function () {var optionSelectedIndex = document.getElementsByTagName('option');hStyle = optionSelectedIndex[document.getElementById('hstyle').selectedIndex].innerHTML;execEditorCommand('formatBlock', hStyle);}function execEditorCommand(name, args = null) {document.execCommand(name, false, args);}document.getElementById('boldBtn').onclick = function () {execEditorCommand('bold', null);}document.getElementById('insertHorizontalRuleBtn').onclick = function () {execEditorCommand('insertHorizontalRule', null);}document.getElementById('insertUnorderedListBtn').onclick = function () {execEditorCommand('insertUnorderedList', null);}document.getElementById('undoBtn').onclick = function () {execEditorCommand('undo', null);}document.getElementById('redoBtn').onclick = function () {execEditorCommand('redo', null);}document.getElementById('paragraphBtn').onclick = function () {execEditorCommand('formatBlock', '<p>');}document.getElementById('createLinkBtn').onclick = function () {let link = window.prompt('请输入链接地址');execEditorCommand('createLink', link);}document.getElementById('insertImageBtn').onclick = function () {let image = window.prompt('请输入图片地址');execEditorCommand('insertImage', image);}
</script>
</html>

简易富文本编辑器

注意点

  • 执行的是原生的 document.execCommand 方法,浏览器自身会对 contenteditable 这个可编辑区维护一个 undo 栈和一个 redo 栈,所以我们才能执行前进和后退的操作,如果我们改写了原生方法,就会破坏原有的栈结构,这时就需要自己去维护,代价很大
  • 如果是 Vue style 里面如果加上 scope 的话,里面的样式对编辑区的内容是不生效的,因为编辑区里面是后来才创建的元素,所以要么删了 scope,要么用 /deep/ 解决(Vue 是这样)。React 的 styled-components 也有类似问题。

android 富文本编辑器_富文本编辑器原理探索相关推荐

  1. 开发地图编辑器_使用地图编辑器开发地图

    存在XML映射以将源XML文档转换为目标XML文档. 映射编辑器获取在"映射编辑器"中创建的映射,并生成XSL文件以在运行时执行实际的XML转换. 在WebSphere Integ ...

  2. android 富文本编辑器_富文本编辑器,还是Tinymce好一点?Angular/Vue集成最新版

    以前jQuery.PC网页时代,富文本编辑器一直就是百度Ueditor.KindEditor.现在使用Angular.Vue.React等MVVM架构以及最新的大前端 工程模式下,老的编辑器显然不更新 ...

  3. kind富文本编辑器_富文本编辑器原理探索

    经常在做企业网站的管理系统的时候需要用到富文本编辑器,之前基本上都是直接去 npm 或者 github 上面搜找一些排名考前或者 readme 写的好的库,直接拿来用.万变不离其宗,是时候探索下本质了 ...

  4. delphi image 编辑器_照片拼图编辑器app下载-照片拼图编辑器下载 v1.0.0 安卓版

    照片拼图编辑器是一个专业的照片编辑的app,app里面有很多的拼图工具,模板.水印.滤镜.贴图等等随便你用,可以将图片拼接成多种样式,满足你的各种需求.你想要什么样的效果都可以,赶紧来下载吧! 应用介 ...

  5. java 设置文本颜色_设置文本中的字体的颜色

    String string=" 欢迎你来到的 jack 的 android 使用技术总结 "; TextV iew info2=(TextView)super.findV iewB ...

  6. lstm 文本纠错_中文文本纠错算法错别字纠正的二三事

    本文首先介绍一下: 1)错别字的类型有哪些 2)错别字纠正的关键技术和关键点 3)简要介绍我们项目中采用的文本纠错框架 4)介绍错别字项目的个人体会 5)几个现成的工具包 ,百度nlp平台最近也推出了 ...

  7. python nlp文本摘要_理解文本摘要并用python创建你自己的摘要器

    我们都与使用文本摘要的应用程序进行交互. 这些应用程序中的许多应用程序都是用于发布有关每日新闻,娱乐和体育的文章的平台. 由于我们的日程安排很忙,因此我们决定在阅读全文之前先阅读这些文章的摘要. 阅读 ...

  8. java精确测量文本高度_基于文本精确计算UITableViewCell的高度

    我正在开发一个ios应用程序,并使用autolayout我正在尝试创建一个具有不同行高的表视图 . 原型单元的布局如下: 我有一个主单元格(黑色)里面有一个UIView(红色),里面有一个UILabe ...

  9. c++源码矢量图形编辑器_下一代代码编辑器的设想

    在通过各种编辑工具使用各类编程语言进行开发的过程中,我们会被大量噪音分心. 举个例子 我们为了美观性,为了代码格式和对齐,我们会大量的插入/删除Space.Tab和Enter. 对于一些同层级的操作, ...

最新文章

  1. 全国大学生智能汽车竞赛英飞凌AURIXTM培训--应用篇 : 3月30日直播
  2. [asp.net core]project.json(1)
  3. android唤醒前台,Android将后台应用唤起到前台的方法 (SDK 4.0, ActivityLifecycleCallbacks)...
  4. 第7章:项目成本管理习题总结
  5. OpenGL之深入解析坐标系
  6. oracle中保留2位小数的写法
  7. 2021年上半年内容型社交电商行业分析报告
  8. Linux系统性能检测
  9. cc=arm-linux,针对基于嵌入式ARM的Linux系统的交叉编译
  10. 人机协作机器人发展趋势_人工智能非万能!智能安防机器人下一站:人机协作...
  11. word表格三线表线宽度
  12. Windows开启SSH连接
  13. 如何修改云服务器连接密码错误,如何修改云服务器连接密码
  14. FileZilla服务器乱码问题
  15. mac系统ps快捷键大全-来自三人行慕课
  16. 解决GitHub中releases下载过慢甚至失败的问题
  17. 浏览器暗黑模式-Dark深色模式
  18. JVM--GC相关记录
  19. 桔子菌和楼下超市田大爷的角色互换经历–Python做的商品价格语音播报器
  20. 二叉树结构——BTree、BTreeNode

热门文章

  1. Android Studio笔记
  2. 双显示器N卡安装ubuntu驱动以及解决办法
  3. 【IOS】获取wifi名称 (即SSID)
  4. Khronos EGL and Apple EAGL
  5. PTA-6-1 数组循环右移 (20分)(C语言)
  6. 信息学奥赛一本通(1042:奇偶ASCII值判断)
  7. Crossing River(信息学奥赛一本通-T1232)
  8. Logistic Regression 之 Sigmoid
  9. 56 SD配置-科目分配-定义物料科目设置组
  10. 47 MM配置-采购-条件-定价过程-定义方案确认