如何在特定的div中获取getSelection()?

7

我有一个可编辑的div(id为'editor1'),允许用户输入文本。然后有一个功能可以使他们对任何高亮文本着色。我的js使用window.getSelection().getRangeAt(0),但问题在于,他们可以突出显示div之外的单词,它们的颜色也会改变。到目前为止,我已经尝试过:

        function red(){
    {       
        var getText = document.getElementById("editor1").innerHTML;
        var selection = getText.getSelection().getRangeAt(0);
        var selectedText = selection.extractContents();
        var span = document.createElement("span");
        span.style.color = "red";
        span.appendChild(selectedText);
        selection.insertNode(span);
    }
    }

JSFiddle: https://jsfiddle.net/xacqzhvq/

可以看到,如果我选中 "this will become red as well" 这句话,我想使用按钮只把这些字变成红色。如何只在 editor1 div 中着色?


它是哪个浏览器?在Chrome 51上它可以工作。 - avck
1
我知道这个函数是有效的,但我不希望除了“editor1” div之外的任何内容也能改变颜色。在fiddle中向下滚动;有一行文本在div之外,也可以使用按钮变成红色 - 我不想要那个;我只想让div内部的任何文本都能够被着色。 - cosmo
3个回答

10
您可以使用.baseNode从选择中获取节点元素。从那里,您可以获取父节点并将其用于比较。
function red(){
    // If it's not the element with an id of "foo" stop the function and return
    if(window.getSelection().baseNode.parentNode.id != "foo") return;
    ...
    // Highlight if it is our div.
}

在下面的示例中,我将div设置为一个id,你可以检查以确保它是该元素: 演示
正如@z0mBi3所指出的那样,这将在第一次运行时奏效。但对于许多高亮显示(如果它们被清除了),可能无法奏效。<span>元素内部的div创建了一个层次结构,其中div是许多span元素的父元素。解决这个问题的方法是遍历节点的祖先,直到找到一个id为"foo"的节点。
幸运的是,你可以使用jQuery来为你执行此操作,只需使用它们的.closest()方法即可。
if($(window.getSelection().baseNode).closest("#foo").attr("id") != "foo") return;

这里有一个使用原生JS实现的.closest()方法的答案。


1
你可能需要递归地检查parentNode,直到达到body,因为contenteditable会在不同的层次结构中创建多个标签。 - z0mBi3
@z0mBi3 说得好,既然这只是一个“高亮一次”的事情,那么它就可以工作。我建议 OP 使用 jQuery 的 .closest() 函数。我会在编辑中提到的。 - Spencer Wieczorek
Firefox没有baseNode,但Chrome和FF都有focusNode,所以我使用了它。 - Duncanmoo
当创建粗体时,通过获取文本的父元素并查找它的文本,可以获得该窗口选择的基本节点。因此,他没有到达亲吻他的主要父元素。所以用以下这行代码替换第一行就可以成功地实现替换:window.getSelection().focusNode.parentElement.closest("#Foo").id != "Foo"将window.getSelection().baseNode.parentNode.id != "Foo"替换为window.getSelection().focusNode.parentElement.closest("#Foo").id != "Foo" - borma425
@SpencerWieczorek https://stackoverflow.com/a/68521823/14592575 - borma425
@YehiaAli 这个问题的第二部分明确回答了这个问题,只需将 <span> 示例替换为 <b> 即可。我直接将 if($(window.getSelection().baseNode).closest("#editor").attr("id") != "editor") return; 插入到你的问题片段中,它可以正常工作。请记住,本地 .closest() 的支持非常有限(没有 Edge/IE),而且在提出这个问题时其他地方也很新。话虽如此,我同意使用 focusNode 要比 baseNode 更好。 - Spencer Wieczorek

3
尝试这段代码:

尝试这段代码:

function addBold(){
 
if(window.getSelection().focusNode.parentElement.closest("#editor").id != "editor") return;

 





  const selection = window.getSelection().getRangeAt(0);
  
  let selectedParent = selection.commonAncestorContainer.parentElement;
  

  let mainParent = selectedParent;
  
  if(selectedParent.closest("b"))
  {
  //Unbold
    var text = document.createTextNode(selectedParent.textContent);
    mainParent = selectedParent.parentElement;
    mainParent.insertBefore(text, selectedParent);
    mainParent.removeChild(selectedParent);
    mainParent.normalize();
  }
  else
  {
    const span = document.createElement("b");
    span.appendChild(selection.extractContents());
    selection.insertNode(span);
    mainParent.normalize();
  }
  

  if (window.getSelection) {
    if (window.getSelection().empty) {  // Chrome
      window.getSelection().empty();
    } else if (window.getSelection().removeAllRanges) {  // Firefox
      window.getSelection().removeAllRanges();
    }
  } else if (document.selection) {  // IE?
    document.selection.empty();
  }




};
<div id="editor" contenteditable="true">

You are the programmers of the future 

</div>


<button onclick="addBold()">Bold</button>

我得到了代码,并添加了以下答案的编辑:
粗体/取消粗体使用Window.getSelection()选择的文本:链接 在特定id内部使用getSelection().focusNode不起作用:链接

1
非常好用!非常感谢!我甚至在Angular中使用了它。 - mamashare

2
你在寻找这个吗,
  //html
  <body>
     <p id='editor1'>asdf</p>
     <button onclick='red()'>
     RED
     </button>
  </body>

  //JavaScript

    window.red = function(){
        //var getText = document.getElementById("editor1").innerHTML;
        var selection = window.getSelection().getRangeAt(0);
        var selectedText = selection.extractContents();
        var span = document.createElement("span");
        span.style.color = "red";
        span.appendChild(selectedText);
        selection.insertNode(span);
    }

Plunker:https://plnkr.co/edit/FSFBADoh83Pp93z1JI3g?p=preview


我已经有可用的函数了,我已经编辑了我的问题以突出显示问题。 - cosmo
很抱歉,我不确定您的问题是什么。您的意思是说,如果您在内部和外部div中都进行了高亮,并且单击按钮时,您只想使内部div中的元素变为红色吗? - Gopinath Shiva
这正是问题所在。我已经链接了一个演示,展示了确切的问题:https://jsfiddle.net/xacqzhvq/ - cosmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接