[JS] Range学习笔记(待补充Selection)

448 阅读1分钟

学习参考资料javascript.info

Range

基本概念

  1. Range翻译过来是范围,可以理解为是一对「边界点」(范围起点、范围终点)
  2. 它可以直接用new来创建。
let range = new Range();
  1. 我们可以用range.setStart(node, offset) and range.setEnd(node, offset)来设定边界起始。其中node可以是文本结点也可以是元素结点。

(1)当node是文本结点时:

<body>
    <p id="para">Alex</p>
</body>
<script>
    const $p = document.getElementById('para');
    let range = new Range();
    range.setStart($p.firstChild, 3);
    range.setEnd($p.firstChild, 4);
    console.log(range.toString()); // x

    range.setStart($p.firstChild, 0);
    range.setEnd($p.firstChild, 1);
    console.log(range.toString()); // A

    range.setStart($p.firstChild, 1);
    range.setEnd($p.firstChild, 4);
    console.log(range.toString()); // lex
    
    // 对于文本可以理解为:offset设置为a,b可以理解为选取index为a到index为b-1的字符
   //  如果offset大于文本长度会报错
</script>

(2)当node是元素结点是:

node是元素结点时,offset需要设置为它子结点的index。例如,p的子结点及其对应index如下: (下划线代表空格)

  • index0: Alex_
  • index1: and
  • index2: his friends
<body>
    <p id="para">Alex <span>and</span> his friends </p>
</body>
   const $p = document.getElementById('para');
    let range = new Range();
    range.setStart($p, 0); // 从index选到index0
    range.setEnd($p, 1);
    console.log(range.toString()); // Alex_


    range.setStart($p, 1); // 从index 1 选到 index1
    range.setEnd($p, 2);
    console.log(range.toString()); // and

    range.setStart($p, 0); 从index0 选到index2
    range.setEnd($p, 3);
    console.log(range.toString()); //Alex and his friends

    range.setStart($p.firstChild, 4);// 从alex的index 4(空格)开始到p的结束
    console.log(range.toString());  //_and his friends

属性

我们上面创建的Range对象(上面代码块输出为and的部分)有如下属性:

image.png

  • startContainerstartOffset 开始位置的容器是p, 开始的offset是1
  • endContainerendOffset 结束位置的容器是p,结束的offset是2
  • collapsed 如果为true则代表开始和结束位置是一样的,也就是说range内容是空的
  • commonAncestorContainer range内最近的公共祖先。这里是p

方法

(1)设置起始点的方法

前面已经用到了两个方法setStartsetEnd。其他的还有:

  • setStartBefore(node) set start at: right before node
  • setStartAfter(node) set start at: right after node
  • setEndBefore(node) 类似上面
  • setEndAfter(node) 
  • selectNode(node) 让Range包含整个节点
  • selectNodeContents(node) 让Range包含整个结点的内容
  • collapse(toStart)  设定是否起始点一样
  • cloneRange() 创建一个和原Range起始点相同的Range

一些小试验: ex1

   <p id="para">Alex <span>and</span> his friends </p>

    <div id="div">Michael <span id="andTwo">and</span> his family </div>
    
    -----
    const $div = document.querySelector('#div');
    const $para = document.querySelector('#para');
    const $andTwo = document.querySelector('#andTwo');
    
    let range = new Range();
    
    range.setStartBefore($div); // 从div开始
    range.setEndAfter($andTwo); // 到and之后结束
    
    console.log(range.toString()); // Michael and 

ex2 试验selectNode和selectNodeContents

    const $div = document.querySelector('#div');
    const $para = document.querySelector('#para');
    const $andTwo = document.querySelector('#andTwo');
    let range1 = new Range();
    let range2 = new Range();

    range1.selectNode($para);
    console.log(range1);

    range2.selectNodeContents($para);
    console.log(range2);

image.png

通过打印两个Range可以看出,

  • 起止offset不同。
  • 起止容器不同。

selectNode中,容器是body(p的直接父元素),offset分别是1和2,也就是选中body的index为1的子元素(body子元素中,index是0的是空白文本,然后接下来p是index1)。它相当于是 range3.setStart($body, 0); range3.setEnd($body, 2);

而selectNodeContents的容器是p,是从index是0的子元素选到index是2的子元素(也就是全部子元素)。

(2)编辑内容

  • deleteContents() 
  • extractContents() – remove range content from the document and return as DocumentFragment
  • cloneContents() – clone range content and return as DocumentFragment
  • insertNode(node) – insert node into the document at the beginning of the range
  • surroundContents(node) – wrap node around range content. For this to work, the range must contain both opening and closing tags for all elements inside it: no partial ranges like <i>abc.

还需要学习selection,这个放到之后有时间再补充。