Как мне найти индекс innerHTML текста, выделенного из textContent?

#javascript

#javascript

Вопрос:

Я пытаюсь запрограммировать простой текстовый редактор для развлечения. Я застрял на этой проблеме. Я хочу добавить жирный шрифт или курсив к выделенному тексту при нажатии кнопки. Я полагаю, что лучший способ сделать это — получить индекс выделенного текста, а затем добавить тег bold / italic вокруг тега в innerHTML. Однако, похоже, я не могу получить позицию / индекс выбранного тега для переноса в innerHTML. Очевидно, что код innerHTML смещен тегами. Есть ли более простой способ сделать это?

Я думал, что найти индекс выделенного текста было правильным решением. Хорошо. К сожалению, indexOf найдет только первое событие.

 var word_document = document.getElementById('word-document');


/* This code is for our bold button */
var bold_button = document.getElementById('bold-button')
bold_button.addEventListener('click', (event) => {


  /* Test to see if text is highlighted */
  let text = window.getSelection().toString();
  console.log("Selected Text: "   text);

  if (text.length > 0) {
      // Find the position of the highlighted text in the word document.
      let position = word_document.innerHTML.indexOf(text);  // Not a good way of doing it
      console.log("Pos: ", position);

      // Replace the highlighted text from the document with the bold text
      word_document.innerHTML.replace(text, "<b>"   text   "</b>");
  }
  /* If text is not highlighted, add a bold tag */
  else {
    // Add bold tag to bottom of document
    word_document.focus();
    word_document.innerHTML  = "<b></b>";
    word_document.selectionEnd = word_document.innerHTML.length - 6;
  }
});

/* This code is for our italic button */
var italic_button = document.getElementById('italics-button');
italic_button.addEventListener('click', function() {

  let text = window.getSelection().toString();
   
   // Same issue

}); 
 <button id="bold-button">B</button>
<button id="italics-button">I</button>
<textarea id="word-document">Starting Text</textarea> 

Я полагаю, что возможным способом было бы перебрать textContent и найти, соответствует ли ему какой-либо текст до выбранного текста, а затем установить переменную для пропуска такого количества совпадений. Есть ли более простой способ сделать это. В идеале я хотел бы создать тег bold или italic и добавить его в текстовую область более правильным образом. Я поддерживаю обход DOM, вероятно, лучший способ. Есть идеи о том, как это можно было бы легче решить?
Спасибо

Я использую обычный / ванильный Javascript.

Редактировать: исправлен код. Добавление JsFiddle здесь

Комментарии:

1. Что такое word_document ? Может быть, вы могли бы сделать это доступным для выполнения фрагментом, который иллюстрирует вашу проблему?

2. @wyck О, мой плохой. Я сделаю. Добавит jsfidddle

3. getRange() возвращает объект диапазона , из которого вы можете получить начало и конец выделения. вам не обязательно использовать indexOf.

4. @Robert позвольте мне поиграть с этим и вернуться к вам.

5. @Robert, это похоже на то, что я хочу сделать. Но мне нужно выбрать родительский узел этой позиции:

Ответ №1:

Вы можете попробовать это :

 <html>
<header>
</header>
<body>
    <button id="bold-button" onClick="makeBold()">B</button>
    <div id="word-document" contenteditable>Starting Text</div>
    <script>
        function makeBold() {
            var inputText = document.getElementById("word-document");
            var innerHTML = inputText.innerHTML;
            text = window.getSelection().toString();
            var index = innerHTML.indexOf(text);
            if (index >= 0) { 
                    innerHTML = innerHTML.substring(0,index)   "<span style='font-weight: bold;'>"   innerHTML.substring(index,index text.length)   "</span>"   innerHTML.substring(index   text.length);
                        inputText.innerHTML = innerHTML;
            }
        }
    </script>
</html> 

идея здесь состоит в том, чтобы использовать поддельную текстовую область: div с редактируемым содержимым. Я надеюсь, что это поможет вам,

Удачи!

Комментарии:

1. Я не использую jQuery, и execCommand был обесценен.

2. Итак, если вы не используете jQuery, попробуйте мое второе предложение, я только что отредактировал свой пост, это может дать подсказку. Удачи, амиго.

3. я думаю, это решение не будет работать, если выделенный текст встречается несколько раз в innerHTML

Ответ №2:

простое фиктивное решение. это не работает для вложенных тегов.

Я настоятельно рекомендую прочитать этот учебник

  function action({tag, classes}, event){
    const text = document.getElementById("word-document");
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    const before = text.innerHTML.substr(0, range.startOffset);
    const after = text.innerHTML.substr(range.endOffset);
    const selected = text.innerHTML.substr(range.startOffset,range.endOffset - range.startOffset );

    const warpped = `<${tag} ${classes ? "class="   classes : ""}>${selected}</${tag}>`
    text.innerHTML = before   warpped   after;
  } 
 #word-document {
  border: 1px solid black;
  padding: 10px;
}

.underline{
  text-decoration-line: underline;
} 
 <button onclick="action({tag: 'b'})">B</button>
<button onclick="action({tag: 'i'})">I</button>
<button onclick="action({tag: 'span', classes:'underline'})">Under score</button>
<div id="word-document" contenteditable>Starting Text</div> 

Комментарии:

1. На самом деле я просто читал этот учебник 😉

2. @DavidFrick итак, сложная часть будет заключаться в том, какой выбор тега начинается с startContainer и заканчивается в endContainer . А затем правильно закрыть и открыть тег, чтобы избежать несоответствия тегов

3. Итак, давайте возьмем этот javascript: « действие функции ({тег, классы}, событие) { // Получаем текстовый документ пусть text = document.getElementById(«word-document»); var start = text.SelectionStart; // получаем индекс последнего выбранного символа var finish = text.selectionEnd; // получить выделенный текст var sel = text.value.substring(start, finish); // сделать что-то с выбранным содержимым console.log(sel.parentNode); } « Поскольку я включен, я должен сделать это таким образом. К сожалению, это также связано с текстовой областью по сравнению с div, который можно редактировать, поскольку

4. Firefox это не нравится

5. вы не можете иметь вложенные теги внутри текстовой области …. вот почему contenteditable . и в firefox может быть много выбранных диапазонов, chrome not’, поэтому из-за этой разницы может возникнуть другое поведение