富文本编辑器开发系列5——浏览器`Selection API`探究

系列文章快速阅读:
富文本编辑器开发系列-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. Selection 基本属性

我们先上示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Selection API</title>
</head>
<body>
    <div id="box">
        <div onclick="showInfo()">
            <p>这里是一段普通的 <span>文字</span></p>
            <p>这里是另一段普通的 <span>文字</span></p>
        </div>
    </div>
</body>
<script>
    function showInfo() {
        var sel = window.getSelection();
        console.log(sel.toString());
    }
</script>
</html>

我们在本地运行起这个示例页面,并且在控制台中的source面板里,在console语句一行打上断点,从右向左选中第二行文字的一部分,然后看看当前的selection是什么样的:

在这里,可以看到当前Selection的所有属性:

  • anchorNode: 锚点,返回该选区起点所在的节点,这里的值是文字所在的文本节点,因为我们是从右向左拖动选择的,所以起点是该节点而不是这里是另一段普通的 所在的文本节点
  • anchorOffset: 锚点偏移量,表示的是选区起点在其所在节点中的位置偏移量,如果起点节点是文本节点,name返回的就是从该文字节点的第一个字开始,到被选中的第一个字之间的字数;如果起点节点是一个元素,则返回的就是在选区第一个节点之前的同级节点总数(这些节点都是起点节点的子节点)。这里我们的节点是文字节点,所以返回的是开始的字在文字这个文本节点中偏移量。
  • focusNode: 该选区终点所在的节点, 这里就是这是一段普通的这部分文字所在的文字节点
  • focusOffset: 与anchorOffset类型,这里是文本节点,并且选中内容在该节点开头,所以偏移量为0
  • isCollapsed: 是否闭合,此处开始节点和结束节点,开始偏移量与结束偏移量皆不相同,所以为false.
  • rangeCount: 包含的拖蓝区域数量,除了firfox外,其它浏览器默认都只有一个
  • type: 类型,这里的值是 Range ,代表当前是一个拖蓝区域

我们修改一下内容:

<p>这里是另一段普通的 <span>文字内容啊</span></p>

然后还是从右向左拖动选择,但选择范围改变一下:

然后再看当前的偏移量:

印证了我们上面的说明。还要注意一点,对于开始节点来说,这里的偏移量是3,意味着选区的开始位置前面有3个字符,即选区是从第4个字符开始的,而对于结束节点,偏移量是4,说明选区结束位置是在该文本节点的第4个字之后。

2. Selection 选区API

getRangeAt(index) 获取拖蓝区域

我们在js部分增加两行代码:

var range = sel.getRangeAt(0);
console.log(range);

还是和上面一样的操作,然后还是在console语句处断点:

image-20200630164803780

可以看到,成功获取到了当前的拖蓝对象,而我们在具体的网页编辑器功能开发中,通常用的最多的也是这个拖蓝对象,它的几个关键属性:

  • collapsed : 描述拖蓝是否闭合,如果我们只是在区域中某个文字后面点击鼠标,并不拖动选中文字,此时选区和拖蓝的开始节点与结束节点是同一个节点,偏移量也都相同,那么我们就说此时选区和拖蓝都是闭合的。
  • startContainer: 拖蓝的开始节点。拖蓝与选区不同,拖蓝的开始节点与选中时拖动方向无关。所以此例中的开始节点就是另一段普通的 所在的文本节点。
  • startOffset:开始节点偏移量,这里是3,同样意味着拖蓝的开始位置在开始节点(文本节点)第3个字符之后。
  • endContainer:拖蓝的结束节点。
  • endOffest:结束节点偏移量,这里是4,意味着拖蓝的结束位置在结束节点(文本节点)的第4个字符之后

collapse(parentNode, offset) 将当前选区闭合到指定节点的指定位置

我们继续在js部分增加代码:

sel.collapse(document.getElementById('box'), 0);

然后还是按照上面的方法操作,这次不再断点。

我们发现,选中内容后点击选区,拖蓝消失了,其实就是选区闭合了,因为现在的页面内容还不是可编辑区域,所以闭合后没有看到有任何光标标识拖蓝闭合的位置。

我们改造下代码:

 <div id="box" contenteditable>
        <div onclick="showInfo()">
            <p id="first">这里是一段普通的 <span>文字</span>内容</p>
            <p id="second">这里是另一段普通的 <span>文字内容啊</span></p>
        </div>
    </div>
    //...
   <script>
    function showInfo() {
        var sel = window.getSelection();
        var range = sel.getRangeAt(0);
        sel.collapse(document.getElementById('first'), 2);
    }
</script>

此时,按照上文的操作完成后,如下:

image-20200630172713899

根据光标位置可知,选区闭合到了IDfirstp元素的第二个节点(<span>文字</span>)之后

在线编辑

extend(node, offset) 将选区焦点移动到特定位置。

此时,从选区中原来拖蓝的结束节点(即使是闭合拖蓝也一样)到指定的位置之间将形成新的拖蓝,原拖蓝将消失。

我们改造下js代码:

var sel = window.getSelection();
var range = sel.getRangeAt(0);
sel.extend(document.getElementById('first'), 1);

仍旧按照上文中的操作,从右向左拖动选中另一段普通的 文字内容, 触发脚本后结果如下:

image-20200630175426041
在线编辑

modify(alter, direction, tranularity) 修改选区

  • alter:操作类型,有两个可取值:

    • move: 移动光标位置
    • extend: 扩展选区范围
  • direction: 移动或扩展方向,有四个可取值

    • forward: 文本前进方向
    • backward : 文本后退方向
    • left : 向左
    • right : 向右
  • tranularity: 颗粒度,按照什么为单位进行移动或扩展

  • character: 每次移动或扩展一个字符的位置

    • word:每次移动或扩展一个单词的位置,英文状态下比较明显,中文状态下有时一个字就是一个单词(例如),有时一个词语是一个单词(例如普通),不确定。
    • sentence:每次移动或扩展一个句子的位置,以句号为分界(中英文句号皆可)。
    • line: 每次移动或扩展一行的位置,如果原开始位置在某行的第N个字符后,那移动或扩展后的位置就是上(下)一行的第N个字符后,如果上(下)一行字符总数小于N,则移动或扩展到行首(尾)。
    • paragraph: 每次移动或者扩展一个段落。偏移位置规则同上。
    • lineboundary: 移动或扩展到行首或行尾(根据方向)。
    • sentenceboundary: 移动或扩展到句首或句尾。
    • paragraphboundary: 移动或扩展到段首或段尾。
    • documentboundary : 移动或扩展到文档开头或结尾。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Selection API</title>
</head>
<body>
    <div id="box" contenteditable>
        <div onclick="showInfo()">
            <p id="first">这里是一段普通的 <span>文字</span>内容</p>
            <p id="second">这里是另一段普通的 <span id="third">文字内容啊</span></p>
            <p>这是一段带有英文的句子: this is a line with english</p>
            <p>这是一段带有英文的多行句子: this is a line with english。这是一段带有英文的多行句子: this is a line with english.这是一段带有英文的多行句子: this is a line with english,这是一段带有英文的多行句子: this is a line with english。这是一段带有英文的多行句子: this is a line with english。这是一段带有英文的多行句子: this is a line with english。这是一段带有英文的多行句子: this is a line with english,这是一段带有英文的多行句子: this is a line with english。</p>
        </div>
    </div>
</body>
<script>
	function showInfo() {
        var sel = window.getSelection();
        var range = sel.getRangeAt(0);
        sel.modify('move','backward', 'character');
        // sel.modify('extend','backward', 'character');
        // sel.modify('extend','forward', 'character');
        // sel.modify('extend','backward', 'word');
        // sel.modify('extend','backward', 'sentence');
        // sel.modify('extend','backward', 'line');
        // sel.modify('extend','backward', 'paragraph');
        // sel.modify('extend','backward', 'lineboundary');
        // sel.modify('extend','backward', 'sentenceboundary');
        // sel.modify('extend','backward', 'paragraphboundary');
        // sel.modify('extend','backward', 'documentboundary');
}
</script>
</html>

可以直接将此代码复制到本地运行,并通过开放关闭js中不同的注释来查看不同参数下操作的差别。


在线编辑

collapseToStart() 取消当前选区,并把光标定位在原选区的最开始处

在线编辑

collapseToEnd() 取消当前选区,并把光标定位在原选区的结束位置

在线编辑

selectAllChildren(parentNode) 把指定元素所有子元素设为选中区域(不包含该元素本身),并取消之前选中区域

在线编辑

addRange(range) 将一个拖蓝区域加入选区当中

在线编辑

removeRange(range) 从选区中移除一个拖蓝区域

由于大多数浏览器一个选区都只能拖动出一个拖蓝区域,所以执行此操作后,用户选中的拖蓝区域将消失,且光标将消失。(注:并不会删除拖蓝区域中的内容)

在线编辑

removeAllRanges() 从当前选区中移除所有的拖蓝区区域

参看addRange在线代码示例中的用法

deleteFromDocument() 从页面中删除选区中的内容

在线编辑

toString() 返回代表当前selection对象的字符串,例如当前选择的文本文字

在线编辑

containsNode(aNode,aPartlyContained) 判断指定节点是否包含在当前选区内

  • aNode: 用于判断是否包含在选区中的那个节点
  • aPartlyContained: 当此参数为true时,即使选区只包含指定节点的一部分内容,该方法也将返回true,当此参数为false时,只有选区完全包含指定节点时,才返回true

在线编辑

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值