2012-03-12 65 views
2

我想遍歷元素中文本的字符並將span添加到字符中。這是使用jQuery.map()很簡單:將跨度添加到字符串中的字符(在HTML元素中)

$elem = $('h1'); 
var chars = jQuery.map($elem.text().split(''), function(c) { 
    return '<span>' + c + '</span>'; 
}); 
$elem.html(chars.join('')); 

以上works great with a simple string,但現在我想改變的功能,使得它也將處理這樣更「複雜」的內容:<h1>T<em>e</em><b>st</b></h1>。其中應該翻譯爲:<h1><span>T</span><em><span>e</span></em><b><span>s</span><span>t</span></b></h1>

這意味着我不能簡單地遍歷元素中的所有字符了。有什麼我可以用來循環元素的內容(字符)以及所有的孩子嗎?還是有另一種實現我想要的方式?

+0

使用jQuery的濾波器濾除只是textnodes和運行那些在你的地圖。 – adeneo 2012-03-12 11:46:54

回答

8

總體思路:

您可以通過子節點遞歸迭代。如果遇到元素節點,則會遍歷其子元素等。如果遇到文本節點,則用一系列span元素替換它。


jQuery的

function wrapCharacters(element) { 
    $(element).contents().each(function() { 
     if(this.nodeType === 1) { 
      wrapCharacters(this); 
     } 
     else if(this.nodeType === 3) { 
      $(this).replaceWith($.map(this.nodeValue.split(''), function(c) { 
       return '<span>' + c + '</span>'; 
      }).join('')); 
     } 
    }); 
}  

wrapCharacters($('h1')[0]); 

DEMO


的JavaScript(jQuery的無)

的想法保持不變,即使沒有jQuery的,包裹每一個字符是不是很困難:

var d_ = document.createDocumentFragment(); 

for(var i = 0, len = this.nodeValue.length; i < len; i++) { 
    var span = document.createElement('span'); 
    span.innerHTML = this.nodeValue.charAt(i); 
    d_.appendChild(span); 
} 
// document fragments are awesome :) 
this.parentNode.replaceChild(d_, this); 

只有遍歷子節點,因爲有文本節點的迭代過程中得到去除,以小心進行。

Plain JavaScript example

+1

通常,更快地創建一個跨度並克隆它,而不是使用createElement。使用類似'element.innerHTML =''+ textNode.data.split('')。join('<\/span>')+'<\/span>';'或者''或''來代替整個文本節點也可能快得多。類似。也包裝空白,也許不是OP想要的東西? – RobG 2012-03-12 13:43:53

+0

是的,克隆可能會更快。但'replaceChild'也會一次替換整個文本節點。目前爲止,將文本節點的內容設置爲HTML字符串已經有效(文本節點隨後被元素節點替換),但我不知道瀏覽器之間的行爲是否一致。 – 2012-03-12 13:48:51

4

嘗試像(未經測試):

function recursivelyWrapTextNodes($node) { 
    $node.contents().each(function() { 
    var $this = $(this); 
    if (this.nodeType === 3) { //Node.TEXT_NODE (IE...) 
     var spans = $.each($this.text().split(""), function(index, element) { 
      var $span = $("<span></span>"); 
      $span.text(element); 
      $span.insertBefore($this); 
     }); 
     $this.remove(); 
    } 
    else if (this.nodeType === 1) //Node.ELEMENT_NODE 
    recursivelyWrapTextNodes($this); 
} 

例子:http://jsfiddle.net/Ymcha/

+1

你忘了包裝每個角色。 – 2012-03-12 11:50:46

+0

@ FelixKling:謝謝 - 剛剛糾正了這一點,並添加了一個例子。 – Matthias 2012-03-12 11:55:55

0

這是一個純JavaScript解決方案

/** 
 
* Enclose every character of a string into a span 
 
* @param text Text whose characters will be spanned 
 
* @returns {string} The "spanned" string 
 
*/ 
 
function spanText(text) { 
 
    return "<span class='char'>" + 
 
     text.split("").join("<\/span><span class='char'>") + "<\/span>"; 
 
} 
 

 
var text = "Every character will be in a span"; 
 
document.getElementById("testContent").innerHTML = spanText(text); 
 

 
document.getElementById("showSpans").textContent = spanText(text);
.char{background-color: grey;}
<! --- Demo for spanning all characters --> 
 
<h3> Spanned text is highlighted grey </h3> 
 
<p id="testContent"> Spanned material here</p> 
 

 
<h3> This is how the above Highlighted text looks </h3> 
 
<p id="showSpans"></p>