【问题标题】:Programmatically select text in a contenteditable HTML element?以编程方式选择 contenteditable HTML 元素中的文本?
【发布时间】:2011-09-02 14:30:54
【问题描述】:

在 JavaScript 中,可以以编程方式选择 inputtextarea 元素中的文本。您可以使用ipt.focus() 聚焦输入,然后使用ipt.select() 选择其内容。您甚至可以使用ipt.setSelectionRange(from,to) 选择特定范围。

我的问题是:有没有办法在 contenteditable 元素中做到这一点?

我发现我可以使用elem.focus() 将插入符号放入contenteditable 元素中,但随后运行elem.select() 不起作用(setSelectionRange 也不起作用)。我在网上找不到任何关于它的信息,但也许我正在寻找错误的东西......

顺便说一句,如果它有什么不同,我只需要它在 Google Chrome 中工作,因为这是一个 Chrome 扩展程序。

【问题讨论】:

    标签: javascript selection contenteditable


    【解决方案1】:

    [更新修复错误]

    这是一个改编自这个答案的示例,它似乎在 Chrome 中运行良好 - Select range in contenteditable div

    var elm = document.getElementById("myText"),
        fc = elm.firstChild,
        ec = elm.lastChild,
        range = document.createRange(),
        sel;
    elm.focus();
    range.setStart(fc,1);
    range.setEnd(ec,3);
    sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
    

    HTML 是:

    <div id="myText" contenteditable>test</div>
    

    【讨论】:

      【解决方案2】:

      如果您想在 Chrome 中选择元素的所有内容(无论是否可编辑),方法如下。这也适用于 Firefox、Safari 3+、Opera 9+(也可能是更早的版本)和 IE 9。您还可以创建低至字符级别的选择。您需要的 API 是 DOM Range(当前规范是 DOM Level 2,另请参阅 MDN)和 Selection,它被指定为 new Range spec (MDN docs) 的一部分。

      function selectElementContents(el) {
          var range = document.createRange();
          range.selectNodeContents(el);
          var sel = window.getSelection();
          sel.removeAllRanges();
          sel.addRange(range);
      }
      
      var el = document.getElementById("foo");
      selectElementContents(el);
      

      【讨论】:

      • 为了获得额外的兼容性,如果从 onfocus 调用,您应该在 setTimeout()requestAnimationFrame() 中调用 selectElementContents()。见jsfiddle.net/rudiedirkx/MgASG/1/show
      • @Dylan:我不确定:问题提到 OP 已经在使用 focus()
      • @Rudie 兼容性适用于哪个应用程序?
      • 在桌面上工作得很好。在移动浏览器上,不起作用。没有做出选择。在 iPhone iOS 11 上尝试过 Safari 和 Chrome。
      • @campbell:至少在 iOS 上,它确实可以在 Safari 上运行,前提是你已经有了选择。否则不,浏览器根本不允许 JavaScript 显示选择,大概是出于用户体验的原因。
      【解决方案3】:

      除了Tim Downs answer,我还做了一个在oldIE中也能用的解决方案:

      var selectText = function() {
        var range, selection;
        if (document.body.createTextRange) {
          range = document.body.createTextRange();
          range.moveToElementText(this);
          range.select();
        } else if (window.getSelection) {
          selection = window.getSelection();
          range = document.createRange();
          range.selectNodeContents(this);
          selection.removeAllRanges();
          selection.addRange(range);
        }
      };
      
      document.getElementById('foo').ondblclick = selectText;​
      

      在 IE 8+、Firefox 3+、Opera 9+ 和 Chrome 2+ 中测试。甚至我已经将它设置为一个 jQuery 插件:

      jQuery.fn.selectText = function() {
        var range, selection;
        return this.each(function() {
          if (document.body.createTextRange) {
            range = document.body.createTextRange();
            range.moveToElementText(this);
            range.select();
          } else if (window.getSelection) {
            selection = window.getSelection();
            range = document.createRange();
            range.selectNodeContents(this);
            selection.removeAllRanges();
            selection.addRange(range);
          }
        });
      };
      
      $('#foo').on('dblclick', function() {
        $(this).selectText();
      });
      

      ...谁有兴趣,所有的咖啡迷都一样:

      jQuery.fn.selectText = ->
        @each ->
          if document.body.createTextRange
            range = document.body.createTextRange()
            range.moveToElementText @
            range.select()
          else if window.getSelection
            selection = window.getSelection()
            range = document.createRange()
            range.selectNodeContents @
            selection.removeAllRanges()
            selection.addRange range
          return
      

      更新:

      如果您想选择整个页面或可编辑区域的内容(标记为contentEditable),您可以通过切换到designMode 并使用document.execCommand 来简单得多:

      有一个很好的starting point at MDNa littledocumentation

      var selectText = function () {
        document.execCommand('selectAll', false, null);
      };
      

      (适用于 IE6+、Opera 9+、Firefoy 3+、Chrome 2+)http://caniuse.com/#search=execCommand

      【讨论】:

        【解决方案4】:

        Rangy 允许您使用相同的代码跨浏览器执行此操作。 Rangy 是用于选择的 DOM 方法的跨浏览器实现。它经过了很好的测试,使这不那么痛苦。没有它,我拒绝触碰 contenteditable。

        你可以在这里找到 rangy:

        http://code.google.com/p/rangy/

        在您的项目中使用 rangy,您始终可以编写此代码,即使浏览器是 IE 8 或更早版本并且具有完全不同的原生 API 用于选择:

        var range = rangy.createRange();
        range.selectNodeContents(contentEditableNode);
        var sel = rangy.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
        

        其中“contentEditableNode”是具有 contenteditable 属性的 DOM 节点。你可以这样获取它:

        var contentEditable = document.getElementById('my-editable-thing');
        

        或者如果 jQuery 已经是您项目的一部分并且您觉得它很方便:

        var contentEditable = $('.some-selector')[0];
        

        【讨论】:

        【解决方案5】:

        由于所有现有答案都处理div 元素,我将解释如何使用spans 来处理。

        span 中选择文本范围时存在细微差别。为了能够传递文本开始和结束索引,您必须使用Text 节点,如here 所述:

        如果 startNode 是 Text、Comment 或 CDATASection 类型的节点, 那么 startOffset 是从开始的字符数 开始节点。对于其他节点类型,startOffset 是子节点的数量 startNode 开始之间的节点。

        var e = document.getElementById("id of the span element you want to select text in");
        var textNode = e.childNodes[0]; //text node is the first child node of a span
        
        var r = document.createRange();
        var startIndex = 0;
        var endIndex = textNode.textContent.length;
        r.setStart(textNode, startIndex);
        r.setEnd(textNode, endIndex);
        
        var s = window.getSelection();
        s.removeAllRanges();
        s.addRange(r);
        

        【讨论】:

        • 真的应该是:r.setStart(e.firstChild,0); r.setEnd(e.lastChild,e.lastChild.textContent.length); 当然你应该检查一下 e.firstChild 实际上不为空。
        • &lt;div&gt;&lt;span&gt; 元素中进行选择没有区别。至少,不像你描述的那样。
        • div 和 span 之间存在差异,在某些情况下,div 的解决方案在 span 中无法正常工作。例如,如果您使用 div 解决方案以编程方式选择文本然后粘贴新内容,它将不会替换整个文本,只会替换一部分,并且 chrome 和 firefox 之间存在差异
        【解决方案6】:

        现代的做事方式是这样的。更多详情MDN

        document.addEventListener('dblclick', (event) => {
          window.getSelection().selectAllChildren(event.target)
        })
        &lt;div contenteditable="true"&gt;Some text&lt;/div&gt;

        【讨论】:

        • 谢谢,这很好用! Fwiw,该 MDN 页面将这项技术标记为实验性的。但它适用于 2020 年 6 月当前版本的 Chrome 和 FF。
        猜你喜欢
        • 2012-08-04
        • 1970-01-01
        • 1970-01-01
        • 2021-01-02
        • 2012-11-09
        • 2021-06-30
        • 1970-01-01
        • 2015-12-24
        相关资源
        最近更新 更多