获取所有标题,并恢复创建一棵树



我想使用标头创建树。

示例:

<h1>Wow</h1>
<h2>Blablablub</h2>
<p>Lorem Ipsum...</p>
<h1>Lalalala</h1>
<p>Lorem Ipsum...</p>
<h1>Ble</h1>
<h2>Test</h2>
<h3>Third</h3>
<p>Lorem Ipsum...</p>

应该创建此列表:

<ul>
    <li>
        <a>Wow</a>
        <ul>
            <li>
                <a>Blablablub</a>
            </li>
        </ul>
    </li>
    <li>
        <a>Lalalala</a>
    </li>
    <li>
        <a>Ble</a>
        <ul>
            <li>
                <a>Test</a>
                <ul>
                    <li>
                        <a>Third</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

a标签应该具有自定义ID,但对于此问题而言并不重要。我试图这样做,但我无法弄清楚。这是我尝试的:

function find_titles(find_num, element, prefix=""){
        temp_list = $("<ul></ul>");
        element.find(`${prefix}h${find_num}`).each(function(i, object){
            let text = $(object).text();
            let id = text.replace(/[^0-9a-zA-Z]/gi, "") + random_chars();
            $(object).attr("id", id);
            if ($(object).next().prop("tagName").toLowerCase() == `h${find_num + 1}`){
                console.log($(object));
                next_titles = find_titles(find_num + 1, $(object), "+ ")[0].innerHTML;
            } else {
                next_titles = "";
            }
            $(`<li><a href="#${id}">${text}</a>${next_titles}</li>`).appendTo(temp_list);
        });
        return temp_list;
    }

编辑

这个:

<h1>First</h1>
<h2>Second</h2>
<p>Lorem Ipsum</p>
<h3>Third</h3>

通常应转换为以下方式:

<ul>
    <li>
        <a>First</a>
        <ul>
            <li>
                <a>Second</a>
            </li>
        </ul>
    </li>
    <li>
        <a>Third</a>
    </li>
</ul>

我不在乎第一个是h1 h2h3。在文本中,这仅对于样式很重要,但在树上并不重要。

您可以首先清除数据以获取heading节点及其数字和文本。之后,您可以使用每个级别的数组和索引编号基于级别来循环数据并构建树结构。

function tree(data) {
  data = Array.from(data).reduce((r, e) => {
    const number = e.nodeName.match(/d+?/g);
    if(number) r.push({ text: e.textContent, level: +number })
    return r;
  }, [])
  const result = $("<ul>")
  const levels = [
    [], result
  ]
  data.forEach(({ level, text }) => {
    const li = $("<li>")
    const a = $("<a>", { text, href: text })
    levels[level + 1] = $('<ul>')
    li.append(a)
    li.append(levels[level + 1]);
    levels[level].append(li)
  })
  return result;
}
const result = tree($("body > *"));
$("body").html(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Wow</h1>
<h2>Blablablub</h2>
<p>Lorem Ipsum...</p>
<h1>Lalalala</h1>
<p>Lorem Ipsum...</p>
<h1>Ble</h1>
<h2>Test</h2>
<h3>Third</h3>
<p>Lorem Ipsum...</p>

您也可以在一个reduce方法中执行此操作,并在元素前进时添加到树中。

function tree(data) {
  const result = $("<ul>")
  const levels = [
    [], result
  ]
  Array.from(data).reduce((r, { textContent: text, nodeName }) => {
    const number = nodeName.match(/d+?/g);
    const level = number ? +number : null;
    if(level) {
      const li = $('<li>').append($("<a>", { text, href: text }))
      r.push({ level: r[level + 1] = $('<ul>') })
      r[level].append(li.append(levels[level + 1]))
    }
    return r;
  }, levels)
  return result;
}
const result = tree($("body > *"));
$("body").html(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Wow</h1>
<h2>Blablablub</h2>
<p>Lorem Ipsum...</p>
<h1>Lalalala</h1>
<p>Lorem Ipsum...</p>
<h1>Ble</h1>
<h2>Test</h2>
<h3>Third</h3>
<p>Lorem Ipsum...</p>

您可以迭代所有 H1元素,然后遍历所有下一个标头元素(除了 H1以外的所有标头元素(。这是一个示例:

const elements = $('h1').map(function() {
  let container = $('<li>');
  const ret = container;
  container.append($('<a>').text($(this).text()));
  let next = $(this).next('h2, h3, h4, h5');
  while (next.length) {
    const tmp = $('<li>');
    tmp.append($('<a>').text(next.text()));
    container.append(tmp);
    container = tmp;
    next = next.next('h2, h3, h4, h5');
  }
  return ret;
}).get();
const parent = $('<ul>');
parent.append(elements);
console.log(parent[0].innerHTML);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Wow</h1>
<h2>Blablablub</h2>
<p>Lorem Ipsum...</p>
<h1>Lalalala</h1>
<p>Lorem Ipsum...</p>
<h1>Ble</h1>
<h2>Test</h2>
<h3>Third</h3>
<p>Lorem Ipsum...</p>

使用:header选择器和tagName属性

let $sub, $ul = $('<ul/>')
$(':header').each(function() {
  let $this = $(this),
      $prev = $this.prev(':header'),
      $parent = $prev.length && $prev.prop('tagName') < $this.prop('tagName') ? $sub : $ul
      
  $parent.append('<li><a>' + $this.text() + '</a></li>')
  $sub = $('<ul/>').appendTo($parent.find('li:last'))
})
$('body').html($ul)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Wow</h1>
<h2>Blablablub</h2>
<p>Lorem Ipsum...</p>
<h1>Lalalala</h1>
<p>Lorem Ipsum...</p>
<h1>Ble</h1>
<h2>Test</h2>
<h3>Third</h3>
<h3>Third</h3>
<p>Lorem Ipsum...</p>
<h1>First</h1>
<h2>Second</h2>
<p>Lorem Ipsum</p>
<h3>Third</h3>
<h1>First</h1>
<h2>Second</h2>
<p>Lorem Ipsum</p>
<h3>Third</h3>

最新更新