利用 javascript 实现富文本编辑器

本文详细介绍了如何利用javascript实现一个富文本编辑器,包括利用contenteditable属性、操作光标、修改文本格式、处理浏览器兼容性问题等方面。在实践中,遇到的诸多坑如回车换行、列表位置错误、插入链接和图片等问题,通过调整和自定义方法得到了解决。此外,还探讨了移动端的特定问题,如键盘遮挡、输入法处理等,并提供了解决方案。
摘要由CSDN通过智能技术生成

近期项目中需要开发一个兼容PC和移动端的富文本编辑器,其中包含了一些特殊的定制功能。考察了下现有的js富文本编辑器,桌面端的很多,移动端的几乎没有。桌面端以UEditor为代表。但是我们并不打算考虑兼容性,所以没有必要采用UEditor这么重的插件。为此决定自研一个富文本编辑器。本文,主要介绍如何实现富文本编辑器,和解决一些不同浏览器和设备之间的bug。


准备阶段

在现代浏览器中已经为我们准备好了许多API来让 html 支持富文本编辑功能,我们没有必要自己完成全部内容。


contenteditable=”true”

首先我们需要让一个 div 成为可编辑状态,加入 contenteditable="true" 属性即可。


<div contenteditable="true" id="rich-editor"></div>

在这样的 <div> 中插入任何节点都将默认是可编辑状态的。如果想插入不可编辑的节点,我们就需要指定插入节点的属性为 contenteditable="false" 。


光标操作

作为富文本编辑器,开发者需要有能力控制光标的各种状态信息,位置信息等。浏览器提供了 selection 对象和 range 对象来操作光标。


selection 对象

Selection对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。


获得一个 selection 对象


let selection = window.getSelection();

通常情况下我们不会直接操作 selection 对象,而是需要操作用 seleciton 对象所对应的用户选择的 ranges (区域),俗称”拖蓝“。获取方式如下:


let range = selection.getRangeAt(0);

由于浏览器当前可能存在多个文本选取,所以 getRangeAt 函数接受一个索引值。在富文本编辑其中,我们不考虑多选取的可能性。


selection 对象还有两个重要的方法, addRange 和 removeAllRanges 。分别用于向当前选取添加一个 range 对象和 删除所有 range 对象。之后你会看到他们的用途。


range 对象

通过 selection 对象获得的 range 对象才是我们操作光标的重点。Range表示包含节点和部分文本节点的文档片段。初见 range 对象你有可能会感到陌生又熟悉,在哪儿看见过呢?作为一个前端工程师,想必你一定拜读过《javascript 高级程序设计第三版》 这本书。在第12.4节,作者为我们介绍了 DOM2 级提供的 range 接口,用来更好的控制页面。反正我当时看的一脸????这个有啥用,也没有这种需求啊。这里我们就大量的用到这个对象。对于下面节点:


<div contenteditable="true" id="rich-editor">

<p>百度EUX团队</p>

</div>

光标位置如图所示:


打印出此时的 range 对象:


其中属性含义如下:


* startContainer: range 范围的起始节点。


* endContainer: range 范围的结束节点


* startOffset: range 起点位置的偏移量。


* endOffset: range 终点位置的偏移量。


* commonAncestorContainer: 返回包含 startContainer 和 endContainer 的最深的节点。


* collapsed: 返回一个用于判断 Range 起始位置和终止位置是否相同的布尔值。


这里我们的 startContainer , endContainer, commonAncestorContainer都为 #text 文本节点 ‘百度EUX团队’。因为光标在‘度‘字后面,所以startOffset 和 endOffset 均为 2。且没有产生拖蓝,所以 collapsed 的值为 true。我们再看一个产生拖蓝的例子:


光标位置如图所示:


打印出此时的 range 对象:


由于产生了拖蓝 startContainer 和 endContainer 不再一致,collapsed 的值变为了 false。startOffset 和 endOffset 正好代表了拖蓝的起终位置。更多的效果大家自己尝试吧。


操作一个 range 节点,主要有如下方法:


setStart(): 设置 Range 的起点

setEnd(): 设置 Range 的终点

selectNode(): 设定一个包含节点和节点内容的 Range

collapse(): 向指定端点折叠该 Range

insertNode(): 在 Range 的起点处插入节点。

cloneRange(): 返回拥有和原 Range 相同端点的克隆 Range 对象

富文本编辑里面常用的就这么多,还有很多方法就不列举了。


修改光标位置


我们可以通过调用 setStart() 和 setEnd() 方法,来修改一个光标的位置或拖蓝范围。这两个方法接受的参数为各自的起终节点和偏移量。例如我想让光标位置到”百度EUX团队”最末尾,那么可以采用如下方法:


let range = window.getSelection().getRangeAt(0),

textEle = range.commonAncestorContainer;

range.setStart(range.startContainer, textEle.length);

range.setEnd(range.endContainer, textEle.length);

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值