以编程方式在可内容编辑的HTML元素中选择文本?


119

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

我的问题是:在contenteditable元素中也有任何方法可以这样做吗?

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

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

Answers:


170

如果要在Chrome中选择某个元素的所有内容(无论内容是否可编辑),方法如下。这也可以在Firefox,Safari 3 +,Opera 9+(可能也是早期版本)和IE 9中使用。您还可以创建字符级别以下的选择。您需要的API是DOM Range(当前规范是DOM Level 2,另请参见MDN)和Selection,它们被指定为新Range规范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);

15
对于额外的了兼容性,你应该调用selectElementContents()一个setTimeout()requestAnimationFrame()如果从一个叫onfocus。参见jsfiddle.net/rudiedirkx/MgASG/1/show
Rudie 2013年

@Dylan:我不确定:问题提到OP已经在使用focus()
Tim Down

4
@Rudie 与哪个应用程序兼容
yckart '16

在桌面上效果很好。在移动浏览器上,不起作用。没有选择。在iPhone iOS 11上尝试过Safari和
Chrome。– campbell

1
@campbell:如果您已经有选择,它至少可以在iOS上的Safari上运行。否则,浏览器只是不允许JavaScript显示选择,这可能是出于用户体验的原因。
蒂姆·唐恩

34

除了Tim Downs的答案,我提出了一个即使在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

在MDN上有一个很好的起点,并提供了一些文档

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

(在IE6 +,Opera 9 +,Firefoy 3 +,Chrome 2+中运行良好)http://caniuse.com/#search=execCommand


10

由于所有现有答案都涉及div元素,因此我将说明如何使用spans。

在中选择文本范围时,会有细微的差别span。为了能够通过文本的开始和结束索引,你必须使用一个Text节点,描述在这里

如果startNode是Text,Comment或CDATASection类型的Node,则startOffset是从startNode开始的字符数。对于其他节点类型,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实际上不为null。
Yorick

2
<div><span>元素中进行选择没有区别。至少不是您所描述的那样。
蒂姆·

div和span之间存在差异,在某些情况下,div的解决方案无法在span中正常工作。例如,如果您使用div解决方案以编程方式选择文本,然后粘贴新内容,则它将不会替换全部文本,只会替换一部分内容,并且chrome和firefox之间会有区别
neosonne

6

Rangy允许您使用相同的代码来执行此跨浏览器。Rangy是用于选择的DOM方法的跨浏览器实现。经过了充分的测试,这减轻了很多痛苦。我拒绝触摸没有它的可编辑内容。

您可以在这里找到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];

Rangy项目现在移至Github:github.com/timdown/rangy
tanius

4

现代的做事方式就是这样。有关MDN的更多详细信息

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


谢谢,这很好!首先,该MDN页面将该技术标记为实验性。但它可以在2020
。– JohnK

2

[已更新,以纠正错误]

这是根据此答案改编而成的示例,该示例在Chrome中似乎效果很好- 在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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.