DOM Range Api

Range Api 1

(必要的 api)

  • var range = new Range();
  • range.setStart(element, 9);
  • range.setEnd(element, 4);
  • var range = document.getSelection().getRangeAt(0);

也就是说,range 有两种创建方式

第一种,new Range()然后 setStart、setEnd

第二种,getSelection 然后 getRangeAt

Range Api 2

(可选的,方便 DOM 操作的 api)

针对单个node 的操作

  • range.setStartBefore
  • range.setEndBefore
  • range.setStartAfter
  • range.setEndAfter
  • range.selectNode
  • range.selectNodeContents

Range Api 3

(拿到 range 了以后可以做的事情)

  • var fragment = range.extractContents()

    fragment 其实是一种文档的片段,当我们 append 一个 fragment 到 DOM 树的时候,append 上去的玩意儿其实是 fragment 里面的所有子元素,而 fragment 并没有挂载到 DOM 树中。

  • range.insertNode(document.createTextNode("aaa"))

    我们使用 document.insertBefore 和 document.appendChild 的时候,只能在两个元素之间或者前后插入元素,而无法精确操作。(元素跟元素之间)

    当使用 range.insertNode的时候,我们可以精确到两个 DOM 之间的具体的 text 中的位置,在该位置插入一个 Node。(文本跟文本之间)

上面这两个 api 的配合使用,有奇效。

实战

eg1

<div id="a">
  <span>1</span>
  <p>2</p>
  <a>3</a>
  <div>4</div>
</div>
<script>
	let element = document.getElementById("a");
  function reverseChildren() {
    let range = new Range();
    range.selectNodeContents(element);
    let fragment = range.extractContents();
    var l = fragment.childNodes.length;
    while(l-- > 0) {
      fragment.appendChild(fragment.childNodes[l]);
    }
    element.appendChild(fragment);
  }
  reverseChildren();
</script>

eg2

<div id="a">
  123456789
</div>
<script>
	let element = document.getElementById('a');
  let range = new Range();
  range.setStart(element, 0);
  range.setEnd(element, 1);
  console.log(range);
  range.extractContent();
</script>

eg3

<div id="a">
  123456789
</div>
<script>
  let element = document.getElementById("a").childNodes[0];
  let range = new Range();
  range.setStart(element, 0);
  range.setEnd(element, 4);
  console.log(range);
  range.extractContents();
</script>

eg4

<div id="a">
  12345<span style="background-color: aqua;">456789</span>01111111111
</div>
<script>
  let range = new Range();
  range.setStart(document.getElementById("a").childNodes[1].childNodes[0], 0);
  range.setEnd(document.getElementById("a").childNodes[2], 3);
  // range.extractContents();
</script>

做富文本编辑器的时候,rangeApi 也很有用,省得光标去乱跳。

不过一般来说,我们也用不到富文本编辑器。

据说,做富文本编辑器,可以到阿里的 p7 的水准了。

不仅仅是一个 DOM 操作,这是一个很复杂的操作

原文地址:https://www.cnblogs.com/ssaylo/p/13278399.html