2013-05-21 6 views
18

У меня есть небольшой текстовый узел:Вставить HTML в текстовый узел с JavaScript

var node 

И я хочу, чтобы обернуть промежуток вокруг каждого вхождения «лол».

node.nodeValue = node.nodeValue.replace(/lol/, "<span>lol</span>") 

Это он печатает "<span>lol<span>", когда я хочу "lol" в качестве поверочного элемента.

+0

в этом случае вы должны repace текстовый узел с контентом HTML –

+0

@ArunPJohny Как сделать это? – alt

+0

@ JacksonGariety - вам нужно заменить текстовый узел новым элементом span и текстовыми узлами DOM или изменить свойство innerHTML своего родителя. Пойдите, напишите, что вы попробуете. – RobG

ответ

3

Вам может понадобиться node быть родительским узлом, таким образом, вы можете просто использовать innerHTML:

node.innerHTML=node.childNodes[0].nodeValue.replace(/lol/, "<span>lol</span>"); 

Здесь node.childNodes[0] относится к фактическому текстовому узлу, и node является его содержащим элементом.

+6

Будьте предупреждены о замене innerHTML содержащего узла разрушает дочерние узлы, которые, возможно, добавили прослушиватели событий через скрипты. – ccjuju

+0

Это не работает для меня (Chrome 50); нет визуального изменения. Я вижу на консоли, что 'node.innerHTML' изменился, но пользовательский интерфейс не изменяется. Кроме того, 'node.parentNode.innerHTML' не содержит нового изменения. – Jeff

15

Следующая статья дает вам код, чтобы заменить текст с HTML-элементами:

http://blog.alexanderdickson.com/javascript-replacing-text

Из статьи:

var matchText = function(node, regex, callback, excludeElements) { 

    excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']); 
    var child = node.firstChild; 

    do { 
     switch (child.nodeType) { 
     case 1: 
      if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1) { 
       continue; 
      } 
      matchText(child, regex, callback, excludeElements); 
      break; 
     case 3: 
      child.data.replace(regex, function(all) { 
       var args = [].slice.call(arguments), 
        offset = args[args.length - 2], 
        newTextNode = child.splitText(offset); 

       newTextNode.data = newTextNode.data.substr(all.length); 
       callback.apply(window, [child].concat(args)); 
       child = newTextNode; 
      }); 
      break; 
     } 
    } while (child = child.nextSibling); 

    return node; 
} 

Использование:

matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) { 
    var span = document.createElement("span"); 
    span.className = "search-term"; 
    span.textContent = match; 
    node.parentNode.insertBefore(span, node.nextSibling); 
}); 

и объяснение :

По существу, правильный способ сделать это ...

  1. перебрать все текстовые узлы.
  2. Найти подстроку в текстовых узлах.
  3. Разделить его на смещение.
  4. Вставьте элемент span между расколом.
13

Ответ, представленный Андреасом Джосасом, неплохой. Однако код имел несколько ошибок, когда поисковый запрос несколько раз появлялся в одном текстовом узле. Вот решение с исправленными ошибками, и, кроме того, вставка учитывается в matchText для удобства использования и понимания. Теперь в обратном вызове создается только новый тег и возвращается обратно в matchText по возврату.

Обновлено функция matchText с исправлением ошибок:

var matchText = function(node, regex, callback, excludeElements) { 

    excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']); 
    var child = node.firstChild; 

    while (child) { 
     switch (child.nodeType) { 
     case 1: 
      if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1) 
       break; 
      matchText(child, regex, callback, excludeElements); 
      break; 
     case 3: 
      var bk = 0; 
      child.data.replace(regex, function(all) { 
       var args = [].slice.call(arguments), 
        offset = args[args.length - 2], 
        newTextNode = child.splitText(offset+bk), tag; 
       bk -= child.data.length + all.length; 

       newTextNode.data = newTextNode.data.substr(all.length); 
       tag = callback.apply(window, [child].concat(args)); 
       child.parentNode.insertBefore(tag, newTextNode); 
       child = newTextNode; 
      }); 
      regex.lastIndex = 0; 
      break; 
     } 

     child = child.nextSibling; 
    } 

    return node; 
}; 

Использование:

matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) { 
    var span = document.createElement("span"); 
    span.className = "search-term"; 
    span.textContent = match; 
    return span; 
}); 

Если вы хотите, чтобы вставить якорь (ссылка) теги вместо пролетных тегов, изменить создать элемент, чтобы быть « «вместо« span »добавьте строку для добавления атрибута href в тег и добавьте« a »в список excludeElements, чтобы ссылки не создавались внутри ссылок.

+1

Я добавил исправление 'regex.lastIndex = 0', чтобы сбросить регулярное выражение при повторном использовании. См. Http://stackoverflow.com/questions/1520800/why-regexp-with-global-flag-in-javascript-give-wrong-results – Jeff

2

Не сказал, что это лучший ответ, но я отправляю то, что я сделал для полноты. В моем случае я уже посмотрел или определил смещения текста, который мне нужно выделить в конкретном узле #text. Это также разъясняет этапы.

//node is a #text node, startIndex is the beginning location of the text to highlight, and endIndex is the index of the character just after the text to highlight  

var parentNode = node.parentNode; 

// break the node text into 3 parts: part1 - before the selected text, part2- the text to highlight, and part3 - the text after the highlight 
var s = node.nodeValue; 

// get the text before the highlight 
var part1 = s.substring(0, startIndex); 

// get the text that will be highlighted 
var part2 = s.substring(startIndex, endIndex); 

// get the part after the highlight 
var part3 = s.substring(endIndex); 

// replace the text node with the new nodes 
var textNode = document.createTextNode(part1); 
parentNode.replaceChild(textNode, node); 

// create a span node and add it to the parent immediately after the first text node 
var spanNode = document.createElement("span"); 
spanNode.className = "HighlightedText"; 
parentNode.insertBefore(spanNode, textNode.nextSibling); 

// create a text node for the highlighted text and add it to the span node 
textNode = document.createTextNode(part2); 
spanNode.appendChild(textNode); 

// create a text node for the text after the highlight and add it after the span node 
textNode = document.createTextNode(part3); 
parentNode.insertBefore(textNode, spanNode.nextSibling); 
+0

Спасибо за это, это был лучший ответ для меня – romuleald

Смежные вопросы