Как выделить текст объекта DOM Range?

Я выделяю некоторый текст на html-странице (открытой в Firefox) с помощью мыши и, используя функции JavaScript, создаю / получаю объект range, соответствующий выделенному тексту.

 userSelection =window.getSelection(); 
 var rangeObject = getRangeObject(userSelection);

Теперь я хочу выделить весь текст, который попадает под диапазон объекта. Я делаю это так,

  var span = document.createElement("span");
  rangeObject.surroundContents(span);
  span.style.backgroundColor = "yellow";

Ну, это работает нормально, только когда rangeobject (начальная точка и конечная точка) находится в одном и том же текстовом узле, тогда он выделяет соответствующий текст.

    <p>In this case,the text selected will be highlighted properly,
       because the selected text lies under a single textnode</p>

Но если диапазон объекта охватывает более одного текстового узла, то он не работает должным образом, он выделяет только те тексты, которые находятся в первом текстовом узле, например

 <p><h3>In this case</h3>, only the text inside the header(h3) 
  will be highlighted, not any text outside the header</p> 

Любая идея, как я могу сделать, все тексты, которые подпадают под rangeobject, выделены, независимо от того, лежит ли диапазон в одном узле или нескольких узлах? Спасибо....

4 ответа

Решение

Я бы предложил использовать documentили TextRange"s execCommand метод, который построен именно для этой цели, но обычно используется в редактируемых документах. Вот ответ, который я дал на аналогичный вопрос:

Следующее должно делать то, что вы хотите. В браузерах, отличных от IE, он включает designMode, применяет цвет фона, а затем снова выключает designMode.

ОБНОВИТЬ

Исправлена ​​работа в IE 9.

ОБНОВЛЕНИЕ 12 сентября 2013

Вот ссылка, подробно описывающая метод удаления бликов, созданных этим методом:

/questions/12398110/udalit-vyidelenie-dobavlennoe-k-vyidelennomu-tekstu-s-pomoschyu-javascript/12398124#12398124

function makeEditableAndHighlight(colour) {
    var range, sel = window.getSelection();
    if (sel.rangeCount && sel.getRangeAt) {
        range = sel.getRangeAt(0);
    }
    document.designMode = "on";
    if (range) {
        sel.removeAllRanges();
        sel.addRange(range);
    }
    // Use HiliteColor since some browsers apply BackColor to the whole block
    if (!document.execCommand("HiliteColor", false, colour)) {
        document.execCommand("BackColor", false, colour);
    }
    document.designMode = "off";
}

function highlight(colour) {
    var range;
    if (window.getSelection) {
        // IE9 and non-IE
        try {
            if (!document.execCommand("BackColor", false, colour)) {
                makeEditableAndHighlight(colour);
            }
        } catch (ex) {
            makeEditableAndHighlight(colour)
        }
    } else if (document.selection && document.selection.createRange) {
        // IE <= 8 case
        range = document.selection.createRange();
        range.execCommand("BackColor", false, colour);
    }
}

Rangy - это кросс-браузерная библиотека выбора и выбора, которая отлично решает эту проблему с помощью модуля CSS Class Applier. Я использую его для реализации подсветки в различных браузерах и на iPad, и он работает отлично.

Ответ Тима Дауна великолепен, но Рэнги избавляет вас от необходимости самостоятельно писать и поддерживать все эти коды обнаружения функций.

       var userSelection = document.getSelection();
var range = userSelection.getRangeAt(0);

Вместо метода SurroundContent вы можете использовать методы appendChild и extractContents следующим образом:

       let newNode = document.createElement('mark');
newNode.appendChild(range.extractContents());
range.insertNode(newNode);

         function markNode() {
if(document.getSelection() && document.getSelection().toString().length){
let range = document.getSelection().getRangeAt(0);
let newNode = document.createElement('mark');
      newNode.appendChild(range.extractContents());
      range.insertNode(newNode);
}
else{
alert('please make selection of text to mark');
}
}

function resetContent() {
      testMe.innerHTML = `Remember: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node">Read</a> and <strong>stay strong</strong>`;
}
         <p id="testMe">Remember: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node">Read</a> and <strong>stay strong</strong></p>


<div><button onclick="markNode()">markNode</button></div>
<div><button onclick="resetContent()">resetContent</button></div>

Не могли бы вы уточнить необходимость этой функциональности. Если вы хотите изменить только стиль выделения выделенного текста, вы можете использовать CSS: '::selection'

Дополнительная информация: http://www.quirksmode.org/css/selection.html https://developer.mozilla.org/en/CSS/::selection

Можете ли вы попробовать добавить класс для окружающего диапазона и применить иерархический CSS?

var span = document.createElement("span");
span.className="selection";
rangeObject.surroundContents(span);

В определении CSS

span.selection, span.selection * {
   background-color : yellow;  
}

Я не пробовал это. Но только догадываюсь, что это сработает.

Другие вопросы по тегам