自定义文档 Selection、Range 属性

发布时间 2023-10-17 09:56:34作者: 长安城下翩翩少年

一 document.execCommand
现阶段 项目中 使用方法document.execCommand 可直接操控选中文本,添加属性(操控文档)。但是由于fdocument.execCommand 方法兼容性不好,浏览器之间的实现不一致,没有一个统一的标准。且自定义程度不高。官方已经将该方法移除。推荐使用 Selection 和 Range 进行操作。
罗列一下 document.execCommand 的一些操作。由于现在项目中还使用这些方法。一方面罗列出来,方便后续进行修改。一方面,为使用 Selection,Range 进行重构打好基础 (到底要重构哪些功能)
前提:可编辑的div 属性。必须在div 上 配置属性 contenteditable = "true"

  1. 复制 选中文本到剪切板 document.execCommand('copy');
  2. 全选文本 document.execCommand('selectall', false, null);
  3. 给选中的文本添加 a标签 document.execCommand('createLink', false, url);
    取消: document.execCommand('unlink');
  4. 在光标出插入一段html , 或者将选中的文本替换成 html;
  5. 修改选中文本的文字颜色 document.execCommand('foreColor', false, value);
  6. 修改选中文本的文字背景色 document.execCommand('backColor', false, value);
  7. 给选中文本添加粗体(B标签) document.execCommand('blod', false, null);
  8. 给选中文本添加斜体 (I 标签)document.execCommand('italic', false, null);
  9. 给选中文本添加 H1,H2 等标题 标签 document.execCommand('formatBlock', false, 'H1');
  10. 给选中文本添加ul , li 标签 document.execCommand('insertUnorderedList', false, null);
  11. 移除选中文本的样式 , document.execCommand('removeFormat', true, 'foreColor'); 由于浏览器兼容性,这个属性在谷歌上 第三个参数不会生效,而是会移除所有样式 ;
    二 Slection 介绍
    Slection 表示,在浏览器上对选区进行高亮的部分。
    事件
  • elem.onselectstart:当选择从 elem 上开始时。例如,用户按下鼠标键并开始移动鼠标,阻止默认行为会使选择无法开始
  • document.onselectionchange:当选择变动时。注意:此事件只能在 document 上监听
    属性
    const selection = window.getSelection();
    注意:这其中,除了火狐浏览器 range 可能存在多个情况下。其他浏览器range 都只允许有一个。所以,下面的属性,也可通过 获取range = selection.getRangeAt(0), 然后通过range 来获取。
  • anchorNode

选择的起始节点

  • anchorOffset

选择开始的 anchorNode 中的偏移量

  • focusNode

选择的结束节点

  • focusOffset:

选择开始处 focusNode 的偏移量

  • isCollapsed:

如果未选择任何内容(空范围)或不存在,则为 true

  • rangeCount

选择中的范围数,除 Firefox 外,其他浏览器最多为 1 。
用于判断火狐浏览器,并对其做特殊处理。
或者全部禁用多个range情况。用户每次添加range 前都对其selection 已有的range 做删除。selection.removeAllRange()

方法
方法
含义

selection.toString()
获取选区内的文本

getRangeAt(i)

获取从 0 开始的第 i 个范围。在除 Firefox 之外的所有浏览器中,仅使用 0

addRange(range)

将 range 添加到选择中。如果选择已有关联的范围,则除 Firefox 外的所有浏览器都将忽略该调用

removeRange(range)

从选择中删除 range

removeAllRanges()

删除所有范围

empty()

removeAllRanges 的别名

Selection 提供操控选择范围的方法,无需使用range
方法
含义

collapse(node, offset)
用一个新的范围替换选定的范围该新范围从给定的 node 处开始,到偏移 offset 处结束

collapseToStart():

折叠(替换为空范围)到选择起点

collapseToEnd()

折叠到选择终点

extend(node, offset)

将选择的 focus 移到给定的 node,位置偏移 offset

setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset)

用给定的起点和终点来替换选择范围,选中它们之间的所有内容

selectAllChildren(node)
选择 node 的所有子节点

deleteFromDocument()
从文档中删除所选择的内容

containsNode(node, allowPartialContainment = false)
检查选择中是否包含 node(特别是如果第二个参数是 true 的话)

注意事项
如果选择已存在,则首先使用 removeAllRanges() 将其清空,然后添加范围,否则除 Firefox 外的所有浏览器都将忽略新范围
某些选择方法例外,它们会替换现有的选择,例如 setBaseAndExtent

三 Range 介绍
range表示
获取range对象

  1. 通过 selecion 来获取: const range = window.getSelection().getRangeAt(0);
  2. 新建一个range : const range = document.createRange();
    range 中属性
    属性
    含义
    startContainer
    起始节点
    startOffset
    起始节点的偏移量
    endContainer
    结束节点
    endOffset
    结束节点偏移量
    collapsed
    布尔值,如果范围在同一点上开始和结束则为 true
    commonAncestorContainer
    在范围内的所有节点中最近的共同祖先节点
    Range 中的方法

方法
含义
设置range 的起点
setStart(node, offset)
将起点设置在 node 中的位置 offset

setStartBefore(node)
将起点设置在 node 前面 ,也就是offset 为0 位置

setStartAfter(node)
将起点设置在 node 后面
设置range 的终点
setEnd(node, offset)
将终点设置为 node 中的位置 offset

setEndBefore(node)
将终点设置为 node 前面

setEndAfter(node)

将终点设置为 node 后面
注:node既可以是元素节点(nodeType=1),也可以是文本节点(nodeType=3);当为文本节点时,offset表示文本偏移位置。当为元素节点时offset表示偏移的子节点数。
将node 节点设置为range的选区

selectNode(node)
设置范围以选择整个 node

selectNodeContents(node)
设置范围以选择整个 node 的内容
克隆选区
range.cloneRange()

创建一个具有相同起点/终点的新范围
将range 进行折叠
collapse

collapse(true) 表示 将选区折叠到 end的一个点,start = end;
collapse(false)表示 将选区折叠到start的一个点,
end = start;
操作范围内内容
插入node操作:
insertNode(node)

在范围的起始处将 node 插入文档.
配合range.collapse(true), 可以在range 结尾处插入node元素。
其中,start 和 end是相对的,需要根据用户的是正向选区还是逆向选区有关。

surroundContents(node)

使用 node 将所选范围内容包裹起来。
要使此操作有效则该范围必须包含其中所有元素的开始和结束标签
不能像 abc 这样的部分范围

deleteContents()
从文档中删除范围内容

extractContents()

从文档中删除范围内容,并将删除的内容作为 DocumentFragment 返回

cloneContents()

复制范围内容,并将复制的内容作为 DocumentFragment 返回
四 使用Selection 和 Range 重构 document.execCommand 方法
function createLink(){
const selection = window.getSelection();
const value = selection.toString();
const range = selection.getRangeAt(0);
const a = document.createElement('A');
a.innerText = value;
a.href = 'https://www.baidu.com';
range.deleteContents();
range.insertNode(a);
}

    function unlink(){
        const
    }
    
    function addTarget(node,targetName){
      if(node.nodeType === 3){
        if(!node.textContent) return;
        const range = document.createRange();
        const b = document.createElement(targetName);
        range.selectNodeContents(node);
        range.surroundContents(b);
      }
      else {
        const child = [...node.childNodes];
        child.forEach((item,index)=>{
          addTarget(item,targetName);
        });
      }
    }
    
    function removeTarget(){
        
    }