从HTML大纲创建分层对象

时间:2014-11-11 18:46:02

标签: javascript jquery html dom recursion

我最终想要创建一个循环遍历DOM顶层的jQuery插件,并将元素添加到对象,直到它到达标题,此时它会推送一个带有该标题文本的对象。

以下兄弟元素将被添加到此新对象,直到遇到新标题 - 如果标题位于同一级别,则像以前一样创建新对象作为父对象的兄弟,并添加DOM兄弟而不是第一个对象;如果标题位于较低级别,则将其添加为第一个对象的子级,并将兄弟DOM元素作为子级添加到该标题对象中;如果它是更高级别的标题,则在最后一个标题对象上方添加一个新对象并继续循环。

示例:

<p>wooo</p>
<h1>stuff</h1>
<p>stuff</p>
<p>more stuff</p>
<h2>yet more stuff</h2>
<p>still more stuff</p>
<h3>even still more stuff</h3>
<p>yep — stuff!</p>
<h1>still yet more stuff</h1>
<p>stuff stuff stuff</p>
<p>stuff stuff stuffarino</p>

...变为

{
  'p_wooo': HTMLElementObject,
  'h1_stuff': {
    'p_stuff': HTMLElementObject,
    'p_more_stuff': HTMLElementObject,
    'h2_yet_more_stuff': {
      'p_still_more_stuff': HTMLElementObject,
      'h3_even_still_more_stuff': {
        'p_yep_stuff': HTMLElementObject,
      }
    },
  },
  'h1_still_yet_more_stuff': {
    'p_stuff_stuff_stuff': HTMLElementObject,
    'p_stuff_stuff_stuffarino': HTMLElementObject
  {
}

此处what I have so far

    var root = $(res)
                .filter('#contents')
                .children()
                .not('style'); // Don't need no stylesheets hurr!

    var sections = root.filter('h1');
    var outline = {};
    for (var i = 0; i < sections.length; i++) {
      var children;
      if (i+1 <= sections.length) {
        children = root.filter(sections[i]).after().nextUntil(sections[i+1]).filter(function(){return $(this).text().trim() !== '';});
      }

      var slug = getSlug($(sections[i]).text(), {separator: '_'});
      outline[slug] = children;
   }

   console.dir(outline);

唉,它只适用于H1s。 如何将其转换为添加H2-H6的递归函数?

1 个答案:

答案 0 :(得分:1)

我将以一个遍历节点并将它们全部添加到同一个tree对象中的示例开始。从这里找出其余部分应该相当容易:

JSBin:http://jsbin.com/bixekutuhe/1/edit?html,js,output

// Helpers
function isNode(el) { return el && el.nodeType === 1; }
function tag(el) { return el.tagName.toLowerCase(); }

var tree = {}, key;
var node = document.body.firstElementChild;

while (isNode(node) && tag(node) !== 'script') { // add blacklists or whitelists that you might need
  key = node.textContent;

  tree[node.tagName.toLowerCase() + '_' +key.split(' ').join('_')] = node;
  node = node.nextElementSibling; // move to next element
}

console.log(tree);


更新

请尝试以下示例:

var tree = {};
var currentTree = tree, tagName, key;
var node = document.body.firstElementChild;

function isNode(el) { return el && el.nodeType === 1; }
function tag(el) { return el.tagName.toLowerCase(); }

while (isNode(node)) {
  tagName = tag(node);
  key = tagName + '_' + node.textContent.trim().split(' ').join('_');

  switch(tagName) {
    case 'h1':
    case 'h2':
    case 'h3':
    case 'h4':
    case 'h5':
    case 'h6':
      if (tagName === 'h1') {
        currentTree = tree[key] = {};
      } else {
        currentTree = currentTree[key] = {};
      }
    break;

    default:
      currentTree[key] = node;
    break;
  }

  // Move to the next element
  node = node.nextElementSibling;
}

console.log(tree);