2013-05-21 19 views
18

ho un po 'di nodo di testo:Insert HTML nel nodo di testo con JavaScript

var node 

e voglio avvolgere un arco intorno ad ogni occorrenza di "lol".

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

E esso stampa "<span>lol<span>" quando voglio "lol" come elemento arco.

+0

in questo caso si dovrà Repace il nodo di testo con i contenuti HTML –

+0

@ArunPJohny Come posso fare? – alt

+0

@ JacksonGariety: è necessario sostituire il nodo di testo con un nuovo elemento di span DOM e nodi di testo o modificare la proprietà innerHTML del genitore. Fai un tentativo, pubblica ciò che provi. – RobG

risposta

3

Potrebbe essere necessario node di essere il nodo principale, in questo modo si può semplicemente utilizzare innerHTML:

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

Qui node.childNodes[0] si riferisce al nodo di testo vero e proprio, e node è il suo elemento contenente.

+6

Stai attento alla sostituzione del innerHTML del nodo contenitore è distruttivo per i nodi figlio che potrebbero aver aggiunto listener di eventi tramite script. – ccjuju

+0

Questo non funziona per me (Chrome 50); non c'è alcun cambiamento visivo. Posso vedere nella console che 'node.innerHTML' è cambiato, ma non ci sono cambiamenti nell'interfaccia utente. Inoltre, 'node.parentNode.innerHTML' non contiene la nuova modifica. – Jeff

15

Il seguente articolo fornisce il codice per sostituire il testo con gli elementi HTML:

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

Dall'articolo:

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

Usage:

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

E la spiegazione :

In sostanza, il modo giusto per farlo è ...

  1. iterare su tutti i nodi di testo.
  2. Trova la sottostringa nei nodi di testo.
  3. Dividerlo allo scostamento.
  4. Inserire un elemento span tra la divisione.
13

La risposta presentata da Andreas Josas è abbastanza buona. Tuttavia il codice aveva diversi bug quando il termine di ricerca appariva più volte nello stesso nodo di testo. Ecco la soluzione con questi bug corretti e inoltre l'inserto è fattorizzato in matchText per un uso e una comprensione più facili. Ora solo il nuovo tag viene costruito nel callback e restituito a matchText con un ritorno.

Aggiornato funzione matchtext con correzioni di bug:

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

Usage:

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

Se si desidera inserire ancoraggio (link) tag al posto del tag span, modificare l'elemento creare ad essere "un "invece di" span ", aggiungi una linea per aggiungere l'attributo href al tag e aggiungi" a "all'elenco excludeElements in modo che i link non vengano creati all'interno dei link.

+1

Ho aggiunto una correzione 'regex.lastIndex = 0' per reimpostare l'espressione regolare durante il riutilizzo. Vedi http://stackoverflow.com/questions/1520800/why-regexp-with-global-flag-in-javascript-give-wrong-results – Jeff

2

Non dicendo che questa è una risposta migliore, ma sto postando ciò che ho fatto per completezza. Nel mio caso ho già osservato o determinato gli scostamenti del testo che dovevo evidenziare in un nodo #text particolare. Questo chiarisce anche i passaggi.

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

Grazie per questo, è stata la migliore risposta per me – romuleald

Problemi correlati