2013-05-21 15 views
18

Mam trochę węzła tekstowego:Insert HTML do węzła tekstowego z JavaScript

var node 

I chcę owijać rozpiętość wokół każdego wystąpienia „lol”.

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

Jest to wypisuje "<span>lol<span>" kiedy chcę "lol" jako element przęsła.

+0

w tym przypadku trzeba będzie repace węzeł tekstowy z treścią HTML –

+0

@ArunPJohny Jak mam to zrobić? – alt

+0

@ JacksonGariety - należy zastąpić węzeł tekstowy nowym elementem DOM span i węzłami tekstowymi lub zmodyfikować jego właściwość innerHTML nadrzędnej. Spróbuj, po czym próbujesz. – RobG

Odpowiedz

3

Może trzeba node być węzeł nadrzędny, w ten sposób można po prostu użyć innerHTML:

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

Tutaj node.childNodes[0] odnosi się do aktualnego węzła tekstowego i node jest jego zawierający elementem.

+6

Ostrzegam o wymianie innerHTML węzła zawierającego jest destrukcyjny dla węzłów potomnych, które mogły mieć detektory zdarzeń dodane za pomocą skryptów. – ccjuju

+0

To nie działa dla mnie (Chrome 50); nie ma widocznych zmian. Widzę w konsoli, że zmieniono 'node.innerHTML', ale nie ma żadnej zmiany w interfejsie użytkownika. Ponadto, 'node.parentNode.innerHTML' nie zawiera nowej zmiany. – Jeff

15

Poniższy artykuł zawiera kod, aby zastąpić tekst z elementami HTML:

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

Z artykułu:

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

Zastosowanie:

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

oraz wyjaśnienia :

Zasadniczo we właściwy sposób, aby to zrobić jest ...

  1. iteracyjne nad wszystkich węzłów tekstowych.
  2. Znajdź podciąg w węzłach tekstowych.
  3. Podziel na przesunięcie.
  4. Wstaw element span pomiędzy split.
13

Odpowiedź przedstawiona przez Andreasa Josasa jest całkiem dobra. Jednak kod miał kilka błędów, gdy wyszukiwane hasło pojawiało się kilka razy w tym samym węźle tekstowym. Oto rozwiązanie z naprawionymi błędami i dodatkowo wstawka jest uwzględniana w matchText dla łatwiejszego użycia i zrozumienia. Teraz tylko nowy znacznik jest tworzony w wywołaniu zwrotnym i przekazywany do matchText przez zwrot.

Updated funkcja matchText z poprawkami:

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

Zastosowanie:

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

Jeśli pragniesz, aby wstawić kotwicę (link) Tagi zamiast znaczniki SPAN, zmień element tworzenia być „ "zamiast" span ", dodaj linię, aby dodać atrybut href do tagu, i dodaj" a "do listy excludeElements, aby linki nie były tworzone wewnątrz odnośników.

+1

Dodałem poprawkę 'regex.lastIndex = 0', aby zresetować wyrażenie regularne podczas ponownego użycia. Zobacz http://stackoverflow.com/questions/1520800/why-regexp-with-global-flag-in-javascript-give-wrong-results – Jeff

2

Nie mówię, że to lepsza odpowiedź, ale publikuję to, co zrobiłem dla kompletności. W moim przypadku już sprawdziłem lub zdeterminowałem przesunięcia tekstu, który musiałem podświetlić w określonym węźle #text. To również wyjaśnia kroki.

//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

Dzięki za to, to była najlepsza odpowiedź dla mnie – romuleald

Powiązane problemy