【问题标题】:"Failed to execute 'addRange' on 'Selection': parameter 1 is not of type 'Range'“无法在‘选择’上执行‘addRange’:参数 1 不是‘Range’类型
【发布时间】:2020-12-18 05:25:47
【问题描述】:

我想在另一个浏览器的一个浏览器的 contenteditable div 中镜像文本选择。代码的简化和相关部分是:

在源浏览器中:

function someFunc() {
  if (window.getSelection().isCollapsed)
       return;
  var range = window.getSelection().getRangeAt(0);
  
  //Send range over websockets to another browser
  sendToAnotherBrowser(...) //Send range

}

在远程浏览器中,我执行以下代码:

 var sel = window.getSelection();
 sel.addRange(range);  //Where range is the range transmitted over webSockets

我收到以下错误:

 "Failed to execute 'addRange' on 'Selection': parameter 1 is not of type 'Range'

问题: 如何通过 websockets 传输“范围”对象?它不是要字符串化和发送的 JSON 对象。我可以以某种方式对其进行序列化,将其更改为base64,然后在接收端反转该过程吗?

【问题讨论】:

    标签: javascript jquery contenteditable textselection


    【解决方案1】:

    你不能序列化对象本身,购买你可以创建一个包含Range对象数据的对象,将它发送到套接字并从那里构建一个新的Range对象。

    const sendRange = range => {
      const {
        startContainer,
        endContainer,
        startOffset, 
        endOffset, 
        collapsed
      } = range;
      const package = JSON.stringify({
        startNodeId: startContainer.id,
        endNodeId: endContainer.id,
        startOffset, 
        endOffset
        collapsed
      });
      sendToAnotherBrowser(package);
    }
    
    const range = window.getSelection().getRangeAt(0);
    sendRange(range);
    

    然后在您构建新对象的其他地方接收它。

    const buildRange = package => {
      const { 
        startNodeId,
        endNodeId,
        startOffset, 
        endOffset, 
        collapsed 
      } = JSON.parse(package);
      const selection = window.getSelection();
      const range = document.createRange();
      const startNode = document.getElementById(startNodeId);
      const endNode = document.getElementById(endNodeId);
      range.setStart(startNode, startOffset);
      range.setEnd(endNode, endOffset);
      if (collapsed) {
        range.collapse();
      }
      selection.addRange(range);
    }
    

    【讨论】:

    • 正确,但 setStart() 需要两个参数。第一个是startNode。我以为我会从范围内得到它,但在远程浏览器中它抱怨:'无法执行'setStart;关于“范围”:参数 1 不是“节点”类型有什么建议吗?
    • 另外,为什么远程浏览器只需要这些属性而不需要范围的其他属性?
    • 我忽略了第一个论点。在这种情况下,我建议您为选择元素提供id 属性并将ID 发送到远程浏览器。有一个getElementById 查询并选择相同的元素。至于你的第二个问题:根据`Range constructor 的例子,只有一个范围的开始和结束来更新选择就足够了。尽管您可能应该对此进行测试以确保它是否有效。
    • 修复了这个问题,应该是 startContainerendContainer。但至于你之前的问题;您似乎应该研究如何识别和区分不同文档中的文本节点。或者开发您自己的系统,在您自己的文档中绘制两点图表并将其转换为另一个文档中的选择。
    • 或者只发送选定的文本并执行正则表达式来查找该文本在远程浏览器中的位置,类似这样。我希望你能想出办法。
    猜你喜欢
    • 2021-05-06
    • 2023-03-04
    • 2018-04-01
    • 2016-02-10
    • 1970-01-01
    • 2021-12-04
    • 2021-02-25
    • 2015-04-23
    相关资源
    最近更新 更多