简体   繁体   中英

How to make a list of headings(h2 elements) from current page and print them into ul in the aside section

I am trying to automatically generate a list of headings (name of the topics) from the current page. It should be displayed in the aside element of the page.

This is what I have so far:

 <main> <h2>Topic 1</h2> <h2>Topic 2</h2> <h2>Topic 3</h2> <h2>Topic 3</h2> </main> <aside> <!--automaticly generated list of heading like: <ul> <li>Topic 1</li> <li>Topic 2</li> <li>Topic 3</li> <li>Topic 4</li> </ul> --> </aside> 

What do I need to do to finish this?

Well, there are different methods. Here you have one!

<main>
  <h2>Topic 1</h2>
  <h2>Topic 2</h2>
  <h2>Topic 3</h2>
  <h2>Topic 3</h2>
</main>
<aside>
  <!--automaticly generated list of heading
  like:
  <ul>
  <li>Topic 1</li>
  <li>Topic 2</li>
  <li>Topic 3</li>
  <li>Topic 4</li>
  </ul>
  -->

</aside>

<script type="text/javascript">

  var //Array with all the elements with tag main. It is a collection
      mainEl = document.getElementsByTagName("main"),
      //Because we only have one main tag, from the previous
      //collection we chose the first elemnt
      //From that element we create a collection with all the h2 inside
      headingsEls = mainEl[0].getElementsByTagName("h2"),
      //collection of elements with "aside" tag
      asideEl = document.getElementsByTagName("aside"),
      //We create the ul that wil hold the list
      ulEl = document.createElement("ul")

  //Go throw the h2 collection and for each element we create a new li element,
  //we pass to it the text content and we put it on the ul
  for(var i = 0; i < headingsEls.length; i++){
    var liEl = document.createElement("li")
    liEl.textContent = headingsEls[i].textContent
    ulEl.appendChild(liEl)
  }

  //the new ul with the list is appended!
  asideEl[0].appendChild(ulEl)
</script>

I have tried to be very descriptive but ask if you have more doubts!

Edited: I forgot that Array.from was implemented in ES2015. Changed the forEach to a for loop instead.

One way, if you're using jQuery, is to use, and in this case create, a simple plugin:

// using an Immediately-Invoked Function Expression
// to create a jQuery plugin, $.fn is the jQuery
// prototype:
(function($) {

  // declaring the 'toc' property on the
  // jQuery prototype as a function, into
  // which options may be passed:
  $.fn.toc = function(opts) {

    // using jQuery.extend to extend
    // the settings Object (the first
    // Object inside of $.extend) with
    // the user-supplied options from
    // the opts Object:
    let settings = $.extend({
        'to': 'aside',
        'link': true
      }, opts),

      // creating elements with jQuery, in order
      // to use jQuery methods later to insert
      // these elements into the document, and to
      // insert other content into them:
      li = $('<li />'),

      // creating and inserting the <ul> object:
      ul = $('<ul />').appendTo(settings.to),
      a = $('<a />'),
      ref;

    // iterating over the passed-in jQuery collection
    // the 'this' here:
    this.each(function() {
      // cloning the created-<li> element:
      li.clone()
        // appending the string of text from
        // the current <h2> element:
        .append(this.textContent)
        // appending the cloned <li> to the
        // previously-created <ul>
        .appendTo(ul);
    });

    // if we should create links, the settings.link
    // property-value is true:
    if (settings.link === true) {

      // again we iterate over the jQuery collection
      // this time with the prop() method to set the
      // id of the current <h2> element:
      this.prop('id', function(i, p) {
        // i: the index of the current element of
        //    the collection amongst the collection,
        // p: the current property-value of the
        //    current element's specified property

        // here we return the existing id if there is one,
        // otherwise we return the localName of the element
        // (same as the tagName but in lowercase) + the
        // underscore character and the index, giving an
        // id of 'h2_0', 'h2_1' etc:
        return p.length ? p : this.localName + '_' + i;

      // iterating over the collection still, this time
      // using each():
      }).each(function(i, e) {
        // i: the index of the current element in
        //    the collection,
        // e: the current DOM node (not jQuery) held
        //    at this point in the collection.

        // storing the <li> element within the <ul>
        // at the same index-point as the current element:
        ref = ul.find('li').eq(i);

        // cloning the created <a> element:
        a.clone()
          // updating its href property to be
          // equal to the id of the current element
          // from the collection, prefaced by a '#':
          .prop('href', '#' + this.id)
          // appending the contents of the <li> held
          // in the ref variable:
          .append(ref.contents())
          // appending the created <a> element into
          // the <li> element:
          .appendTo(ref);
      });
    }

    // returning the created <li> elements
    // albeit append would itself return the original
    // collection, the 'this' from the plugin:
    return ul.find('li');
  };
})(jQuery);

$('h2').toc();

 (function($) { $.fn.toc = function(opts) { let settings = $.extend({ 'to': 'aside', 'link': true }, opts), li = $('<li />'), ul = $('<ul />').appendTo(settings.to), a = $('<a />'), ref; this.each(function() { li.clone().append(this.textContent).appendTo(ul); }); if (settings.link === true) { this.prop('id', function(i, p) { return p.length ? p : this.localName + '_' + i; }).each(function(i, e) { ref = ul.find('li').eq(i); a.clone().prop('href', '#' + this.id).append(ref.contents()).appendTo(ref); }); } return ul.find('li'); }; })(jQuery); $('h2').toc(); 
 :target { color: #f90; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <main> <h2>Topic 1</h2> <h2>Topic 2</h2> <h2>Topic 3</h2> <h2>Topic 4</h2> </main> <aside></aside> 

JS Fiddle demo .

To use without creating links back to the <h2> elements, simply set links: false in the Object passed to the plugin:

$('h2').toc({
  'link': false
});

 (function($) { $.fn.toc = function(opts) { let settings = $.extend({ 'to': 'aside', 'link': true }, opts), li = $('<li />'), ul = $('<ul />').appendTo(settings.to), a = $('<a />'), ref; this.each(function() { li.clone().append(this.textContent).appendTo(ul); }); if (settings.link === true) { this.prop('id', function(i, p) { return p.length ? p : this.localName + '_' + i; }).each(function(i, e) { ref = ul.find('li').eq(i); a.clone().prop('href', '#' + this.id).append(ref.contents()).appendTo(ref); }); } return ul.find('li'); }; })(jQuery); $('h2').toc({ 'links': false }); 
 :target { color: #f90; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <main> <h2>Topic 1</h2> <h2>Topic 2</h2> <h2>Topic 3</h2> <h2>Topic 4</h2> </main> <aside></aside> 

JS Fiddle demo .

References:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM