โดยทางโปรแกรมเลือกข้อความในองค์ประกอบ HTML ที่แก้ไขเนื้อหาได้หรือไม่


119

ใน JavaScript คุณสามารถเลือกข้อความในองค์ประกอบinputหรือtextareaองค์ประกอบโดยทางโปรแกรมได้ คุณสามารถมุ่งเน้นการป้อนข้อมูลที่มีและจากนั้นเลือกเนื้อหาของมันด้วยipt.focus() คุณยังสามารถเลือกช่วงที่เฉพาะเจาะจงกับipt.select()ipt.setSelectionRange(from,to)

คำถามของฉันคือมีวิธีใดบ้างที่จะทำสิ่งนี้ในcontenteditableองค์ประกอบด้วย

ฉันพบว่าฉันสามารถทำได้elem.focus()เพื่อใส่คาเร็ตในcontenteditableองค์ประกอบ แต่การรันในภายหลังelem.select()ไม่ได้ผล (และไม่ทำsetSelectionRange) ฉันไม่พบสิ่งใดในเว็บเกี่ยวกับเรื่องนี้ แต่บางทีฉันกำลังค้นหาสิ่งที่ผิด ...

อย่างไรก็ตามถ้ามันสร้างความแตกต่างฉันต้องการให้มันทำงานใน Google Chrome เท่านั้นเพราะนี่คือส่วนขยายของ Chrome

คำตอบ:


170

หากคุณต้องการเลือกเนื้อหาทั้งหมดขององค์ประกอบ (แก้ไขเนื้อหาได้หรือไม่) ใน Chrome มีวิธีการดังนี้ สิ่งนี้จะใช้งานได้ใน Firefox, Safari 3+, Opera 9+ (อาจเป็นเวอร์ชันก่อนหน้านี้ด้วย) และ IE 9 คุณยังสามารถสร้างตัวเลือกลงไปจนถึงระดับตัวละครได้ API ที่คุณต้องการคือ DOM Range (ข้อมูลจำเพาะปัจจุบันคือDOM ระดับ 2โปรดดูที่MDN ) และ Selection ซึ่งระบุเป็นส่วนหนึ่งของข้อมูลจำเพาะช่วงใหม่ ( เอกสาร MDN )

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

@Dylan: ผมไม่แน่ใจว่า: คำถามที่กล่าวว่า OP focus()ที่มีอยู่แล้วโดยใช้
Tim Down

4
@Rudie Compatibilityสำหรับแอปพลิเคชันใด
yckart

ใช้งานได้ดีบนเดสก์ท็อป บนเบราว์เซอร์มือถือไม่ทำงาน ไม่มีการเลือก ลอง Safari และ Chrome บน iPhone iOS 11
campbell

1
@campbell: ทำงานบน Safari อย่างน้อยบน iOS หากคุณมีตัวเลือกอยู่แล้ว มิฉะนั้นเบราว์เซอร์จะไม่อนุญาตให้ JavaScript แสดงการเลือกโดยสันนิษฐานว่าเป็นเพราะเหตุผลด้านประสบการณ์ของผู้ใช้
Tim Down

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 เป็นโหนดประเภทข้อความข้อคิดเห็นหรือ CDATASection ดังนั้น 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 นั้นไม่เป็นโมฆะ
Yorick

2
มีความแตกต่างระหว่างการเลือกในไม่เป็น<div>และ<span>องค์ประกอบ อย่างน้อยก็ไม่ใช่อย่างที่คุณอธิบาย
Tim Down

มีความแตกต่างระหว่าง div และ span ในบางกรณีโซลูชันสำหรับ div ไม่ทำงานในช่วงที่เหมาะสม ตัวอย่างเช่นหากคุณเลือกข้อความทางโปรแกรมด้วยโซลูชัน 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" คือโหนด DOM ที่มีแอตทริบิวต์ contenteditable คุณอาจได้รับสิ่งนี้:

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>


ขอบคุณมันใช้งานได้ดีมาก! Fwiw หน้า MDN นั้นทำเครื่องหมายว่าเทคโนโลยีนี้เป็นการทดลอง แต่ใช้งานได้ใน Chrome และ FF เวอร์ชันปัจจุบันในเดือนมิถุนายน 2020
JohnK

2

[อัปเดตเพื่อแก้ไขข้อผิดพลาด]

นี่คือตัวอย่างที่ดัดแปลงมาจากคำตอบนี้ซึ่งดูเหมือนจะใช้ได้ดีใน Chrome - เลือกช่วงใน div content ที่แก้ไขได้

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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.