所以我解析一个文档,以便用stackHeadings()获取所有标题。我这样做是为了使用buildNav()构建Microsoft Word样式文档映射。这目前工作正常,但它不是非常强大,并且随着标题不遵循严格的顺序而中断......例如(如果你从一个H2开始它就会断开,如果你将H3嵌套在其中,而H1则会断开,等等......)
我无法找到解决此问题的最佳方法(使其更加强大)。我正在利用jQuery的`nextUntil'函数来查找两个h1之间的所有h2。
一种可能性是取代:
elem.nextUntil( 'h' + cur, 'h' + next )
与
elem.nextUntil( 'h' + cur, 'h' + next + ',h' + (next + 1) + ',h' + (next + 2) ... )
找到同一级别的两个标题之间的所有子标题。但是现在h3s的h3孩子只会嵌套一层而不是两层。
那么你必须将当前的标题级别与父级标题级别进行比较,如果有多个跳转(h1 - > h3),则必须在它们之间创建一个空子项为缺少h2的嵌套占位符。
非常感谢任何想法或解决方案!
stackHeadings = (items, cur, counter) ->
cur = 1 if cur == undefined
counter ?= 1
next = cur + 1
for elem, index in items
elem = $(elem)
children = filterHeadlines( elem.nextUntil( 'h' + cur, 'h' + next ) )
d.children = stackHeadings( children, next, counter ) if children.length > 0
d
filterHeadlines = ( $hs ) ->
_.filter( $hs, ( h ) -> $(h).text().match(/[^\s]/) )
buildNav = ( ul, items ) ->
for child, index in items
li = $( "<li>" )
$( ul ).append( li )
$a = $("<a/>")
$a.attr( "id", "nav-title-" + child.id )
li.append( $a )
if child.children
subUl = document.createElement( 'ul' )
li.append( subUl )
buildNav( subUl, child.children )
items = stackHeadings( filterHeadlines( source.find( 'h1' ) ) )
ul = $('<ul>')
buildNav( ul, items)
答案 0 :(得分:5)
我把一些能做你想做的事情的http://jsfiddle.net/fA4EW/
组合在一起这是一个相当简单的递归函数,它使用一系列元素(节点)并相应地构建UL结构。为了与问题保持一致,当你从H1到H3等时,我添加了占位符(空)列表元素。
function buildRec(nodes, elm, lv) {
var node;
// filter
do {
node = nodes.shift();
} while(node && !(/^h[123456]$/i.test(node.tagName)));
// process the next node
if(node) {
var ul, li, cnt;
var curLv = parseInt(node.tagName.substring(1));
if(curLv == lv) { // same level append an il
cnt = 0;
} else if(curLv < lv) { // walk up then append il
cnt = 0;
do {
elm = elm.parentNode.parentNode;
cnt--;
} while(cnt > (curLv - lv));
} else if(curLv > lv) { // create children then append il
cnt = 0;
do {
li = elm.lastChild;
if(li == null)
li = elm.appendChild(document.createElement("li"));
elm = li.appendChild(document.createElement("ul"));
cnt++;
} while(cnt < (curLv - lv));
}
li = elm.appendChild(document.createElement("li"));
// replace the next line with archor tags or whatever you want
li.innerHTML = node.innerHTML;
// recursive call
buildRec(nodes, elm, lv + cnt);
}
}
// example usage
var all = document.getElementById("content").getElementsByTagName("*");
var nodes = [];
for(var i = all.length; i--; nodes.unshift(all[i]));
var result = document.createElement("ul");
buildRec(nodes, result, 1);
document.getElementById("outp").appendChild(result);
答案 1 :(得分:3)
你可以简单地使用jQuery TOC plugin,看起来他们是doing it这样:
$('h1,h2,h3').each(function(i, heading) {
...
}
当然,这只会平等地处理所有h1
,h2
和h3
并通过仅考虑元素的嵌套和文档顺序来创建TOC。但这不是理想的行为吗?
如果h3
直接位于h1
内,在TOC中双重缩进,那将会很奇怪。如果您不能忍受这种不一致,我会考虑清理HTML并将h2
转换为h3
。
h2
。
答案 2 :(得分:0)
基于@LastCoder答案的Jquery + Coffescript解决方案 http://jsfiddle.net/Sydky/1/
buildRec = (headingNodes, $elm, lv) ->
# each time through recursive function pull a piece of the jQuery object off
node = headingNodes.splice(0,1)
if node && node.length > 0
curLv = parseInt(node[0].tagName.substring(1))
if curLv is lv # same level append an il
cnt = 0
else if curLv < lv # walk up then append il
cnt = 0
loop
$elm = $elm.parent().parent()
cnt--
break unless cnt > (curLv - lv)
else if curLv > lv # create children then append li
cnt = 0
loop
li = $elm.children().last() # if there are already li's at this level
if ($elm.children().last().length == 0)
li = $("<li>").appendTo($elm);
$elm = $("<ul>").appendTo(li);
cnt++
break unless cnt < (curLv - lv)
li = $("<li>").appendTo($elm);
li.text(node[0].innerText);
# recursive call
buildRec headingNodes, $elm, lv + cnt
使用
headingNodes = $('#entry').children().filter(":header")
result = $('<ul>')
buildRec(headingNodes,result,1)
result.html()