2012-03-12 46 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>