最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - jQuery: very simple tab switching - Stack Overflow

programmeradmin2浏览0评论

I'm trying to create a very simple tab switching mechanism using jQuery (it's for a WordPress plugin where all tabs show fields that must belong to the same form.)

My goal is: 1) the clicked tab gets highlighted as active; 2) the content referred to the clicked tab gets visible taking the place of the previously displayed content; 3) only the currently active content must be visible and only its tab must be highlighted.

My HTML code is something like this:

    <html>
      <body>
      <h2 class="nav-tab-wrapper">
        <a href="#tab-1" class="nav-tab nav-tab-active">First</a>
        <a href="#tab-2" class="nav-tab">Second</a>
        <a href="#tab-3" class="nav-tab">Third</a>
      </h2>
      <hr />
      <section id="tab-1" class="tab-content active">
        <P>Some content here.</P>
      </section>
      <section id="tab-2" class="tab-content hidden">
        <p>Some more here.</p>
      </section>
      <section id="tab-3" class="tab-content hidden">
        <p>Something else here.</p>
      </section>
    </body>
  </html>

and my broken jQuery code is:

(function( $ ) {
    $('h2.nav-tab-wrapper > a').click(function(event) {
    // Clicked anchor: prevent browser from taking action.
    event.preventDefault();

    // jQuery selector to display tab content.
    var active_tab_selector = $('h2.nav-tab-wrapper > a').attr('href');

    // Find the activated navigation and remove '.active'.
    var activated_nav = $('h2.nav-tab-wrapper > a.nav-tab-active');
    activated_nav.removeClass('nav-tab-active');

    // Add '.active' to the clicked navigation.
    $(this).parents('a').addClass('nav-tab-active');

    // Hide the displayed tab content.
    $(active_tab_selector).removeClass('active');
    $(active_tab_selector).addClass('hidden');

    // Show target tab content.
    var target_tab_selector = $(this).attr('href');
    $(target_tab_selector).removeClass('hidden');
    $(target_tab_selector).addClass('active');
  });
})( jQuery );

It doesn't work as expected. You can try it on JSFiddle (with some minimum CSS omitted here.)

I'm new to jQuery. What am I missing or doing wrong?

Thank you in advance.

I'm trying to create a very simple tab switching mechanism using jQuery (it's for a WordPress plugin where all tabs show fields that must belong to the same form.)

My goal is: 1) the clicked tab gets highlighted as active; 2) the content referred to the clicked tab gets visible taking the place of the previously displayed content; 3) only the currently active content must be visible and only its tab must be highlighted.

My HTML code is something like this:

    <html>
      <body>
      <h2 class="nav-tab-wrapper">
        <a href="#tab-1" class="nav-tab nav-tab-active">First</a>
        <a href="#tab-2" class="nav-tab">Second</a>
        <a href="#tab-3" class="nav-tab">Third</a>
      </h2>
      <hr />
      <section id="tab-1" class="tab-content active">
        <P>Some content here.</P>
      </section>
      <section id="tab-2" class="tab-content hidden">
        <p>Some more here.</p>
      </section>
      <section id="tab-3" class="tab-content hidden">
        <p>Something else here.</p>
      </section>
    </body>
  </html>

and my broken jQuery code is:

(function( $ ) {
    $('h2.nav-tab-wrapper > a').click(function(event) {
    // Clicked anchor: prevent browser from taking action.
    event.preventDefault();

    // jQuery selector to display tab content.
    var active_tab_selector = $('h2.nav-tab-wrapper > a').attr('href');

    // Find the activated navigation and remove '.active'.
    var activated_nav = $('h2.nav-tab-wrapper > a.nav-tab-active');
    activated_nav.removeClass('nav-tab-active');

    // Add '.active' to the clicked navigation.
    $(this).parents('a').addClass('nav-tab-active');

    // Hide the displayed tab content.
    $(active_tab_selector).removeClass('active');
    $(active_tab_selector).addClass('hidden');

    // Show target tab content.
    var target_tab_selector = $(this).attr('href');
    $(target_tab_selector).removeClass('hidden');
    $(target_tab_selector).addClass('active');
  });
})( jQuery );

It doesn't work as expected. You can try it on JSFiddle (with some minimum CSS omitted here.)

I'm new to jQuery. What am I missing or doing wrong?

Thank you in advance.

Share Improve this question asked Feb 28, 2019 at 13:47 Alessandro MaselliAlessandro Maselli 1672 silver badges8 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 5

Using sibling() selector

$('.nav-tab').click(function(e) {
  //Toggle tab link
  $(this).addClass('nav-tab-active').siblings().removeClass('nav-tab-active');

  //Toggle target tab
  $($(this).attr('href')).addClass('active').siblings().removeClass('active');
});
.nav-tab-active {
  color: #f00;
}

.tab-content {
  display: none;
}

.tab-content.active {
  display: block;
}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<h2 class="nav-tab-wrapper">
  <a href="#tab-1" class="nav-tab nav-tab-active">First</a>
  <a href="#tab-2" class="nav-tab">Second</a>
  <a href="#tab-3" class="nav-tab">Third</a>
</h2>
<hr />
<section id="tab-1" class="tab-content active">
  <P>Some content here.</P>
</section>
<section id="tab-2" class="tab-content">
  <p>Some more here.</p>
</section>
<section id="tab-3" class="tab-content">
  <p>Something else here.</p>
</section>

Several things I would remend:

  1. The wrapper should include the tab content panes as well. This way if you have multiple tab containers on the same page, the wrapper knows which tabs and panes belong together.

  2. Write jQuery features using a plugin. Defining $.fn.tabs allows us to do things like $(selector).tabs() instead of putting a big mess of code in our (function ($) { ... })(jQuery) on-ready block

  3. the hidden class is redundant and making your program harder to write. If a tab (or tab content pane) has the active class, it is active - otherwise it is not active.

  4. Because the plugin toggles active on all child ponents in a wrapper, this may cause screen flickering (depending on your CSS) if we click on a tab that is already active. We should prevent the plugin from firing on active tabs.

  5. Use event delegation with .on to attach an event listener to each wrapper instead of using .click to attach an event listener to each tab. Using more event listeners results in programs that are slower to respond to events. Use as few listeners as possible.

  6. It'd be nice if we could customize which tab and content pane is initially active. Perhaps the user clicks /about#contact-us and that goes to the About page with the Contact Us tab active. Unless the HTML has the active class set for the Contact Us tab, it will not be displayed. This is a more advanced feature, so we cover it in a separate section at the end of this answer.

Here's a full working demo. Adjustments have been made to include remendations above -

// write new features as a plugin
$.fn.tabs = function () {
  // for each tab wrapper ... 
  return this.each(function () {
    // capture wrapper context
    var wrapper = this
    // use single click event per wrapper, delegate  only to inactive tabs
    $(wrapper).on('click', '.nav-tab:not(.active)', function (event) {
      // remove all active
      $('.active', wrapper).removeClass('active')
      // get the clicked tab
      var clicked = $(event.target)
      // add the active class
      clicked.addClass('active')
      // find the tab's content and add the active class
      $(clicked.attr('href'), wrapper).addClass('active')
    })
  })
};

// keep on-ready function nice and clean!
(function ($) {
  $('.tab-wrapper').tabs()
})(jQuery)
.nav-tab.active {
  font-weight: bold;
}

.tab-content {
  display: none
}

.tab-content.active {
  display: inherit;
}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="tab-wrapper">
  <nav>
    <a href="#tab-1" class="nav-tab active">First</a>
    <a href="#tab-2" class="nav-tab">Second</a>
    <a href="#tab-3" class="nav-tab">Third</a>
  </nav>
  <hr />
  <section id="tab-1" class="tab-content active">
    <P>Tab Contents 1</P>
  </section>
  <section id="tab-2" class="tab-content">
    <p>Tab Contents 2</p>
  </section>
  <section id="tab-3" class="tab-content">
    <p>Tab Contents 3</p>
  </section>
</div>

<div class="tab-wrapper">
  <nav>
    <a href="#tab-1" class="nav-tab active">First</a>
    <a href="#tab-2" class="nav-tab">Second</a>
    <a href="#tab-3" class="nav-tab">Third</a>
  </nav>
  <hr />
  <section id="tab-1" class="tab-content active">
    <P>Some content here.</P>
  </section>
  <section id="tab-2" class="tab-content">
    <p>Some more here.</p>
  </section>
  <section id="tab-3" class="tab-content">
    <p>Something else here.</p>
  </section>
</div>


How to pass options to plugins -

As a beginner, it's unlikely you have have written your own jQuery plugin before. As you can see above, there's almost nothing to it. The one piece missing is the ability to send options or arguments to the plugin -

// make our function accept an argument, userOptions
$.fn.tabs = function (userOptions) {
  // merge default options with userOptions
  var options =
    $.extend(true, $.fn.tabs.defaults, userOptions || {})

  return this.each(function () {
    // capture wrapper context
    var wrapper = this
    // setup event listener (truncated)
    $(wrapper).on('click', '.nav-tab:not(.active)', ...)
    // click the initial tab  
    $(options.initialTab, wrapper).click()
  });
};

// default options
$.fn.tabs.defaults =
  { initialTab: '.nav-tab:eq(0)' };

Now if you forget to put active class on your tabs or panes, the plugin will still activate the initial tab based on the default selector, the first tab, .nav-tab:eq(0).

To create a tab container with a custom initial tab, we pass an option to our plugin. For example the third tab, .nav-tab:eq(2) -

$('.tab-wrapper').tabs({ initialTab: '.nav-tab:eq(2)' })

Remove the ACTIVE from all to set the active on the designed tab.

$('.nav-tab').click(function(e){

var target_tab_selector = $(this).attr('href');

 $('.tab-content').addClass('hidden');
 $('.tab-content').removeClass('active');
    $(target_tab_selector).removeClass('hidden');
    $(target_tab_selector).addClass('active');

})
.active{display:block}
.hidden{display:none}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
      <body>
      <h2 class="nav-tab-wrapper">
        <a href="#tab-1" class="nav-tab nav-tab-active">First</a>
        <a href="#tab-2" class="nav-tab">Second</a>
        <a href="#tab-3" class="nav-tab">Third</a>
      </h2>
      <hr />
      <section id="tab-1" class="tab-content active">
        <P>Some content here.</P>
      </section>
      <section id="tab-2" class="tab-content hidden">
        <p>Some more here.</p>
      </section>
      <section id="tab-3" class="tab-content hidden">
        <p>Something else here.</p>
      </section>
    </body>
  </html>

The first thing that is missing is to hide all the "active" ones when you click on some tab. Add:

$('.tab-content').removeClass('active');

after your preventDefault() and give it a try.

发布评论

评论列表(0)

  1. 暂无评论