JS 文本操作基础 范围对象 Range

1,189 阅读2分钟

对一段文字进行编辑基础操作之一就是框选。比如想在页面上复制一段文字,我们可以用鼠标选中,然后ctrl+c。其实浏览器也给我们提供丰富的框选操作API,如果你想基于contenteditable属性实现富文本编辑器,这些API是必不可少的存在。

Range对象

想要操作用户选择区域要做两件事:

  1. 告诉浏览器一段范围
  2. 对范围进行选择操作 Range对象就是对一个连续内容范围描述

可以通过以下3种方式获得Range对象:

// 方式1,隶属于Document对象的Range()构造函数
let range1 = new Range()

// 方式2,document.createRange()
let range2 = document.createRange()

// 方式3,Selection.getRangeAt()
let selection = window.getSelection()
let range3 = selection.getRangeAt(0)
// 参数「index」表示选择区域的索引,一般是0,Firefox中可以选中多个区域
// 此种方式内涵了起始位置信息

有了Range还没用,作为一个描述区域的对象,一个空的Range对象没有任何意义,我们必须指定它的起始和终止位置。Range对象给我们提供了两个方法:

  • setStart(node, offset)
  • setEnd(node, offset)

直接上代码:

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<script>
  let range = new Range()

  range.setStart(p, 0)
  range.setEnd(p, 2)

  // 范围的 toString 以文本形式返回其内容(不带标签)
  alert(range) // Example: italic
  console.log(range) // Range{...}

  // 将此范围应用于文档选择(后文有解释)
  document.getSelection().addRange(range)
</script>

setStart和setEnd都有两个参数,参数一node是目标Node节点,它一般可以是Element或者Text对象。如果是Element对象(比如上例),第二个offset参数表示标签元素的(从0开始)第几个子元素(的前方定位):

image.png

如果nodeTextoffset则表示文本的(从0开始)第几个字符(的前方定位):

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<script>
  let range = new Range();

  range.setStart(p.firstChild, 2);
  range.setEnd(p.querySelector('b').firstChild, 3);

  alert(range); // ample: italic and bol

  // 使用此范围进行选择(后文有解释)
  window.getSelection().addRange(range);
</script>

image.png

Range属性

  • 上图中startContainer, startOffset 起始节点的偏移量 = 2
  • 上图中endContainer, endOffset 结束节点的偏移量 = 3
  • collapsed 布尔值,表示范围是否在同一点上开始和结束(无选中内容)
  • commonAncestorContainer 范围内所有节点的最近共同祖先节点,本例中为#p

Range方法

  • 起点
    • setStart(node, offset)
    • setStartBefore(node) 将起点设在node前面
    • setStartAfter(node) 将起点设在node后面
  • 终点
    • setEnd(node, offset)
    • setEndBefore(node) 将终点设在node前面
    • setEndAfter(node) 将终点设在node后面
  • 整个node
    • selectNode(node) 选择节点内容
    • selectNodeContents(node) 选择节点内容
    • collages(toStart) 为trueend=start(收缩到头部),否则start=end(收缩到末尾)
    • cloneRange() 拷贝范围
  • 操作内容
    • deleteContents() 删除范围内容
    • extractContents() 删除范围内容,并返回包裹DocuemntFragment(DOM节点容器)的被删内容
    • cloneContents() 复制范围内容,返回包裹DocuemntFragment的选中内容
    • insertNode(node) 在范围的起始处将node插入文档
    • surroundContents(node) 使用node将范围内容包裹起来。该范围必须包含范围内所有元素的开始和结束标签,不能想<i>abc这样

以上。 原创不易,欲转先告知,欢迎加我交流:

image.png