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

IT技术 javascript selection contenteditable
2021-01-24 05:09:18

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

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

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

顺便说一句,如果它有什么不同,我只需要它在谷歌浏览器中工作,因为这是一个 Chrome 扩展。

6个回答

如果要在 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);
@Rudie对哪个应用程序的兼容性
2021-03-13 05:09:18
@Dylan:我不确定:问题提到 OP 已经在使用focus().
2021-03-17 05:09:18
为了额外的兼容性,您应该调用selectElementContents()asetTimeout()或者requestAnimationFrame()如果从onfocus. 参见jsfiddle.net/rudiedirkx/MgASG/1/show
2021-03-29 05:09:18
@campbell:它至少在 iOS 上可以在 Safari 上运行,前提是您已经有了 selection否则,浏览器根本不允许 JavaScript 显示选择,大概是出于用户体验的原因。
2021-04-07 05:09:18
在桌面上效果很好。在移动浏览器上,不起作用。没有选择。在 iPhone iOS 11 上尝试了 Safari 和 Chrome。
2021-04-12 05:09:18

除了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

由于所有现有答案都涉及div元素,因此我将解释如何使用spans来实现

span. 为了能够通过文本的开始和结束索引,你必须使用一个Text节点,描述在这里

如果 startNode 是 Text、Comment 或 CDATASection 类型的节点,则 startOffset 是距 startNode 开头的字符数。对于其他 Node 类型,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 实际上不是空的。
2021-03-24 05:09:18
在 a<div><span>元素中进行选择没有区别至少,不像你描述的那样。
2021-03-26 05:09:18
div 和 span 之间存在差异,在某些情况下,div 的解决方案在 span 中不起作用。例如,如果您使用 div 解决方案以编程方式选择文本然后粘贴新内容,它将不会替换整个文本,只会替换一部分,并且 chrome 和 firefox 之间存在差异
2021-04-06 05:09:18

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

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

谢谢,这很好用!Fwiw,那个 MDN 页面将这项技术标记为实验性的。但它适用于 2020 年 6 月的当前版本的 Chrome 和 FF。
2021-04-11 05:09:18

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];
Rangy 项目现已移至 Github:github.com/timdown/rangy
2021-03-13 05:09:18