javascript - Programmera för att välja text i ett contenteditable HTML-element?


I JavaScript är det möjligt att programmässigt markera text i ett input eller textarea-element. Du kan fokusera ett input med ipt.focus() och sedan markera dess innehåll med ipt.select(). Du kan till och med markera ett specifikt intervall med ipt.setSelectionRange(from,to).

Min fråga är: finns det något sätt att göra detta i ett contenteditable-element också?

Jag upptäckte att jag kan göra elem.focus() för att sätta markören i ett contenteditable-element, men att sedan köra elem.select() fungerar inte (och det gör inte setSelectionRange heller). Jag kan inte hitta något på nätet om det, men kanske söker jag efter fel sak...

Förresten, om det spelar någon roll, behöver jag bara att det fungerar i Google Chrome, eftersom detta är för en Chrome-tillägg.

Svar #1

Om du vill markera allt innehåll i ett element (oavsett om det är contenteditable eller inte) i Chrome, här är hur. Detta fungerar också i Firefox, Safari 3+, Opera 9+ (möjligen även tidigare versioner) och IE 9. Du kan också skapa markeringar ner till teckennivå. API:erna du behöver är DOM Range (nuvarande specifikation är DOM Level 2, se även MDN) och Selection, som specificeras som en del av en ny Range-specifikation (MDN-dokumentation).

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);

Svar #2

Förutom Tim Downs svar, gjorde jag en lösning som fungerar även i gamla IE:

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;

Testad i IE 8+, Firefox 3+, Opera 9+ och Chrome 2+. Jag har till och med satt upp det i ett jQuery-plugin:

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();
});

...och som är intresserad av, här är samma sak för alla kaffeälskare:

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

Uppdatering:

Om du vill markera hela sidan eller innehållet i ett redigerbart område (markerat med contentEditable) kan du göra det mycket enklare genom att byta till designMode och använda document.execCommand:

Det finns en bra utgångspunkt på MDN och lite dokumentation.

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

(fungerar bra i IE6+, Opera 9+, Firefox 3+, Chrome 2+) http://caniuse.com/#search=execCommand

Svar #3

Det moderna sättet att göra saker på är så här. Mer information på MDN

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

Svar #4

Eftersom alla de befintliga svaren handlar om div-element, kommer jag att förklara hur man gör det med span-element.

Det finns en subtil skillnad när man väljer ett textintervall i en span. För att kunna ange textens start- och slutindex måste du använda en Text-nod, som beskrivs här:

Om startNode är en Nod av typen Text, Kommentar eller CDATASection, är startOffset antalet tecken från början av startNode. För andra Nodtyper är startOffset antalet barnnoder mellan början av 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);

Relaterade artiklar