Универсальный jQuery-скрипт для блоков с вкладками (табами)

Универсальный jQuery-скрипт для блоков с вкладками (табами)

Содержание: Вступление Код jQuery-скрипта для переключаемых блоков с вкладками Добавлено 07.03.2010 (обновлено 09.04.2015) Скачать HTML-код, который нужно использовать для скрипта Обязательные CSS-стили для вышеуказанного HTML-кода Примеры к содержанию ↑Вступление Мое знакомство с фреймворком jQuery произошло в 2008-м году, после того, как, однажды, на ...

Полезные комментарии (8)
Комментарии (952)
  1. 1
    Руслан

    Подскажите, как сделать так, чтобы вкладки открывались, с перезагрузкой страницы?

  2. 2
    Влад

    Огромнейшее спасибо!

  3. 3
    Никита

    А не подскажете как сделать чтобы табы переключались автоматически, по аналогии со слайдером? Спасибо!

  4. 5
    Алексей

    Здравствуйте. Подскажите пожалуйста как сделать так чтобы вкладки все были закрыты и открывались только при клике? например как на авито при просмотре объявления. Спасибо…

  5. 7
    Олег

    Здравствуйте, подскажите пожалуйста как ограничить высоту табов, чтобы на больших вкладках появлялась полоса прокрутки? Спасибо.

  6. 12
    Иван

    Здравствуйте! Хорошая статья и демки. Хотел спросить: можно ли работать с этими табами в php коде в том смысле что содержимое отдельного таба это страничка php типа подгрузка без перезагрузки или это совсем другая история? Я имею ввиду подключение содержимого таким образом сама суть вопроса в том будут ли они сразу все подключены или по мере переключения табов будут прогружатся? Не утяжелит ли этот способ (что я придумал) загрузку сайта — вот что более всего волнует. Благодарю заранее за помощь!

  7. 14
    Иван

    Извиняюсь забыл нажать php при вставке кода «…подключение содержимого таким образом

    <? include(stranichka.php'); ?>...

    «

  8. 15
    Иван

    Спасибо большое. Поищу тогда другое решение. Но ваше тоже сохранил себе, мало ли что. С сайтами работаю давно, пригодится еще и ваше решение.

  9. 16
    Васиий

    Добрый день! Использую плагин с доступам к табам по ссылке с якорем. Стала задача реализовать закрытие вкладки по повторному клику на активную. Т.е. кликаем на активную вкладку, она закрывается. Не могу догадаться как осуществить( Подскажите пожалуйста, что можно сделать?

  10. 17
    Денис

    Спасибо большое за приведенный код, есть модификация его с обработкой hssh-tag и автивацией нужного таба по нему, но не как не могу завязать список табок где class=»active» будет вписан не в li списка а в его ссылке, т.е. чтобы было 1-я вкладка

    	<script>
    		$(function(){
    				var hash = location.hash;
    				if ( hash !== '') {
    					console.log('hash ' + hash);
    					var i = $('ul.tabs__caption li').has('a[href*=' + hash + ']').index();
    					console.log('i ' + i);
    					$('ul.tabs__caption li').has('a[href*=' + hash + ']').addClass('active').siblings().removeClass('active')
    					.closest('div.tabs').find('div.tabs__content').removeClass('active').eq(i).addClass('active');
    				}
    
    				$('ul.tabs__caption').on('click', 'li:not(.active) a', function() {
    			 $(this).parent()
    			 .addClass('active').siblings().removeClass('active')
    			 .closest('div.tabs').find('div.tabs__content').removeClass('active').eq($(this).parent().index()).addClass('active');
    			 });
    		});
    	</script>
    <div class="tabs">
    
     <ul class="tabs__caption">
     <li class="active"><a href="#tab1>1-я вкладка</a></li>
     <li><a href="#tab2">2-я вкладка</a></li>
     <li><a href="#tab3">3-я вкладка</a></li>
     </ul>
    
     <div class="tabs__content active">
     текст 1
     </div>
    
     <div class="tabs__content">
     текст 2
     </div>
    
     <div class="tabs__content">
     текст 3
     </div>
    
    </div>
  11. 18
    Виталий

    Подскажите, пожалуйста, какие изменения необходимо внести, чтобы работала вложенность табов, т .е чтобы можно было бы размещать табы в табах?

  12. 20
    Виталий
    $(document).on('click','li:not(.current)',function() {
    $(this).addClass('current').siblings().removeClass('current')
    .parents('div.section').eq(0).find('>div.box').hide().eq($(this).index()).show(); 
    })

    Не работало, сделал так как показано выше, заработало. Может, что не так?

  13. 21
    lunt

    я совсем дремучий юзер, осваивающий html-верстку методом тыка. применив рекомендации статьи у себя на сайте, ничего не смог сделать — выводится простой маркированный список. долго ковырял примеры автора и вдруг обнаружил, что автор почему-то в разделе «Обязательные CSS-стили» своей статьи забыл упомянуть про указания в CSS на .tabs и .tabs__caption .tabs__caption li. Как только я их прописал, у меня на сайте все заработало в виде переключаемых вкладок, а до этого просто выводило маркированный список безо всяких вкладок.

  14. 23
    madman

    Красава!!!
    Просто и очень красиво и качественно , пригодилось!

  15. 24
    dima

    Здрасти, а как сделать чтобы класс актив добавлялся к ссылки и переключались блоки? Спасибо

  16. 25
    nickcinee

    В вашем варианте

     $('ul.tabs__caption').on('click', 'li:not(.active)', function() {
     $(this)
     .addClass('active').siblings().removeClass('active')
     .closest('div.tabs').find('div.tabs__content').removeClass('active').eq($(this).index()).addClass('active');
     });
    

    preventDefault не срабатывает, если ссылка имеет активный класс.

    Вот как я решил проблему.

    	$('.tabs-menu li').on('click', function(e) {
    		$(this)
    			.addClass('current').siblings().removeClass('current')
    			.closest('.tabs').find('.tabs-content').removeClass('current').eq($(this).index()).addClass('current');
     			e.preventDefault();
    	});
    
  17. 26
    Виталий

    Добрый день, скажите, а как сделать так чтобы кнопки вкладок и контент вкладок находились в разных блоках? Например:

    <div class="tabs">
     <ul>
     <li>Вкладка 1</li>
     <li>Вкладка 2</li>
     </ul>
    </div>
    <div class="content_tabs">
     <div class="tab_content>...</div>
     <div class="tab_content>...</div>
    </div>
    
  18. 28
    Серый

    Dimox, ты молодец, отличные табы!
    До этого поставил jQuery UI с localStorage, использовал как меню с подменю на всех страницах сайтах.
    Заметил заметные тормоза при открытии некоторых страниц, даже скачав к себе все подключаемые файлы.
    Твой вариант в сто раз лучше, общий вес на порядок меньше, тормозов нет!

  19. 29
    Серый

    Dimox, подскажи, как подправить 4-й вариант, чтобы при переходе по ссылке с якорем, указывающим на номер таба, вместо #tab1, #tab2 на сторонних ссылках, были свои, разные якори.

    т.е. для сторонних ссылок прописать уникальные индификаторы, а на табы добавить атрибуты , например

    	<ul class="tabs__caption">
    		<li class="active" data-name="my_tab_1">Первая вкладка</li>
    		<li data-name="text">Вторая вкладка</li>
    	</ul>
    
    <a href="#my_tab_1">современности</a>
    <a href="#text">гедонизма</a>
    

    Просто, возникла ситуация, что на сайте много табов с вложениями и якорями, и если добавлять или удалять какую-то вкладку, то нужно проверять соответствие всех якорей, а если они будут именные, то ничего менять не нужно будет. Надеюсь, данный вариант будет полезен еще кому-то, Спасибо большое за табы!

    • 30

      Замените:

      var tabIndex = window.location.hash.replace('#tab','')-1;
      if (tabIndex != -1) $('ul.tabs__caption li').eq(tabIndex).click();
      

      на:

      var tabIndex = window.location.hash.replace('#','');
      if (tabIndex != -1) $('ul.tabs__caption li[data-name="' + tabIndex +'"]').click();
      

      И замените:

      $('a[href*=#tab]').click(function() {
      	var tabIndex = $(this).attr('href').replace(/(.*)#tab/, '')-1;
      	$('ul.tabs__caption li').eq(tabIndex).click();
      });
      

      на:

      $('a[href*=#]').click(function() {
      	var tabIndex = $(this).attr('href').replace(/(.*)#/, '');
      	$('ul.tabs__caption li[data-name="' + tabIndex +'"]').click();
      });
      
  20. 31
    NeilDaniels

    Что надо дописать к

     Содержимое первого блока
     

    чтобы табы можно было открывать как ссылки вида index.php#tab1, ну и возвращаться из внешнего php-скрипта

    header "location: index.php#tab1"

    ?

  1. 1

    Видимо, это косяк Файерфокса. А по поводу Вконтакте вот тут описывал решение.

  2. 2
    evgen

    путем нехитрых манипуляций делаем Ваш скрипт еще более универсальным

    (function($) {
    	$(function() {
    
    		$('ul.tabs').delegate('li:not(.current)', 'click', function() {
    			$(this).addClass('current').siblings().removeClass('current')
    				.parents('div.section').eq(0).find('>div.box').hide().eq($(this).index()).show();
    			return false;
    		})
    
    	})
    })(jQuery)
    
    <div class="section">
    
    	<ul class="tabs">
    		<li class="current">Первая вкладка</li>
    		<li>Вторая вкладка</li>
    		<li>Третья вкладка</li>
    		<li>Червертая вкладка</li>
    	</ul>
    
    	<div class="box visible">
    	<!-- Inner Tabs -->
    		<div class="section">
    			<ul class="tabs">
    				<li class="current">inner 1</li>
    				<li>inner 2</li>
    			</ul>
    			<div class="box visible">
    				<h2>inner 1</h2>
    				<p> text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
    			</div>
    			<div class="box">
    				<h2>inner 2</h2>
    				<p> text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
    			</div>
    		</div>
    	<!--End Inner Tabs-->
    		<h2>1</h2>
    		<p> Закон внешнего мира, как принято считать, реально рассматривается знак, отрицая очевидное. Гегельянство творит катарсис, хотя в официозе принято обратное. Апперцепция подчеркивает смысл жизни, ломая рамки привычных представлений. Представляется логичным, что адживика откровенна.</p>
    	</div>
    
    	<div class="box">
    		<h2>2</h2>
    		<p> Закон внешнего мира, как принято считать, реально рассматривается знак, отрицая очевидное. Гегельянство творит катарсис, хотя в официозе принято обратное. Апперцепция подчеркивает смысл жизни, ломая рамки привычных представлений. Представляется логичным, что адживика откровенна.</p>
    		<p>Априори, закон внешнего мира принимает во внимание естественный гедонизм, ломая рамки привычных представлений. Концепция реально творит гедонизм, учитывая опасность, которую представляли собой писания Дюринга для не окрепшего еще немецкого рабочего движения.</p>
    		<p>Созерцание осмысляет трансцендентальный бабувизм, хотя в официозе принято обратное. Бабувизм абстрактен. Знак, следовательно, понимает под собой субъективный язык образов, ломая рамки привычных представлений. Деонтология непредвзято подчеркивает даосизм, при этом буквы А, В, I, О символизируют соответственно общеутвердительное, общеотрицательное, частноутвердительное и частноотрицательное суждения.</p>
    	</div>
    
    	<div class="box">
    		<h2>3</h2>
    		<p>Структурализм, как следует из вышесказанного, заполняет из ряда вон выходящий дуализм, однако Зигварт считал критерием истинности необходимость и общезначимость, для которых нет никакой опоры в объективном мире. Суждение осмысляет интеллект, однако Зигварт считал критерием истинности необходимость и общезначимость, для которых нет никакой опоры в объективном мире.</p>
    		<p>Сомнение, по определению, непредвзято заполняет знак, изменяя привычную реальность. Современная ситуация, следовательно, подрывает трагический смысл жизни, однако Зигварт считал критерием истинности необходимость и общезначимость, для которых нет никакой опоры в объективном мире. Гносеология категорически порождает и обеспечивает непредвиденный смысл жизни, отрицая очевидное.</p>
    	</div>
    
    	<div class="box">
    		<h2>4</h2>
    		<p>Деонтология создает примитивный даосизм, открывая новые горизонты. Даосизм, как принято считать, амбивалентно представляет собой примитивный структурализм, не учитывая мнения авторитетов. Предмет деятельности транспонирует язык образов, учитывая опасность, которую представляли собой писания Дюринга для не окрепшего еще немецкого рабочего движения.</p>
    		<p>Даосизм, по определению, создает здравый смысл, учитывая опасность, которую представляли собой писания Дюринга для не окрепшего еще немецкого рабочего движения. Сомнение, следовательно, преобразует гений, ломая рамки привычных представлений. Сомнение трогательно наивно.</p>
    		<p>Жизнь откровенна. Предмет деятельности, как следует из вышесказанного, абстрактен. Искусство, как следует из вышесказанного, нетривиально. Гетерономная этика непредвзято понимает под собой смысл жизни, при этом буквы А, В, I, О символизируют соответственно общеутвердительное, общеотрицательное, частноутвердительное и частноотрицательное суждения.</p>
    		<p>Здравый смысл, как принято считать, творит бабувизм, отрицая очевидное. Суждение, следовательно, амбивалентно. Искусство, по определению, подчеркивает данный позитивизм, открывая новые горизонты. Единственной космической субстанцией Гумбольдт считал материю, наделенную внутренней активностью, несмотря на это заблуждение рефлектирует субъективный дуализм, не учитывая мнения авторитетов.</p>
    	</div>
    
    </div>
    

    теперь можно создавать вложенные табы

  3. 3
    ITech

    Ура! Решил у себя проблему с перепрыгиванием в начало страницы при переключении табов! Вот живой пример: http://injoit.com/what-we-do/

    Реализовал твой код, Dimox, на своем сайте с небольшими изменениями. Вся загвоздка в том, что все div.box необходимо обтянуть еще одним div и для него определить фиксированную высоту!

    Так как у меня контент в табах на сайте постоянно меняется, подключил механизм Math.max.apply для расчета максимально возможной высоты вложенного дива .box. Эту высоту и задавал внешнему диву..

    Для эффекта появления использовал вместо show() animate() с указанием четких параметров:

    (function($) {
    $(function() {
    
    	$('ul.tabs').delegate('li:not(.current)', 'click', function() {
    		$(this).addClass('current').siblings().removeClass('current')
    		.parents('div.section').find('div.box').hide().eq($(this).index()).animate({height: 'auto', width: 'auto', opacity: 'show'}, 'slow');
    	})
    
    /*--Определение максимальной высоты для блока-контейнера .box-wrap--*/
    	Array.max = function(array) {
     return Math.max.apply(Math,array);
     };
    	var heights = $('.box-wrap div.box').map(function() {
     return $(this).innerHeight();
     }).get();
    	$(".box-wrap").height(Array.max(heights));
    /*--------*/
    
    })
    })(jQuery)
    

    И собственно HTML:

    <div class="section vertical">
    <ul class="tabs">
    	<li class="current"><span>Mobile</span></li>
    	<li><span>Social and Web</span></li>
    	<li><span>Cloud</span></li>
    </ul>
    <div class="box-wrap">
    <div class="box visible">
    ---
    </div>
    <div class="box">
    ---
    </div>
    <div class="box">
    ---
    </div>
    </div>
    </div>
    

    Не знаю, правильно я сделал или нет, но главное ведь, что оно работает) Буду рад услышать твои комментарии по данному поводу.

  4. 4

    По теме перепрыгивания вверх при переключении табов.
    В комментариях выше был модифицированный скрипт с определением высоты родительского блока, но если например в табы положить меню-аккордеон (оно там прекрасно работает), то при задании фона табам аккордеон будет вылазить за их пределы.
    И так как вся соль заключается в установке определённой высоты блоку-родителю, можно поступить проще:
    Мне лично помогла установка min-height для родительского блока табов.

    .section {
    	min-height: 1px;
    	}

    проверял в ie7> и нормальных браузерах — вроде бы работает.

  5. 5
    maqsim

    Вместо:
    $(‘ul.tabs’).delegate(‘li:not(.current)’, ‘click’, function() {

    Поставьте:
    $(‘ul.tabs li:not(.current)’).live(‘click’, function() {

    Проблема первого элемента в том, что некорректно связываются события через метод delegate, когда разметка с вкладками подгружена через ajax. Второй вариант работает отлично + мы делаем 1 раз выборку, а не 2

  6. 6
    Metaller

    Проблема прыгающей страницы при переключении табов в том, что в момент переключения сначала прячется содержимое всех табов, а потом показывается содержимое активного таба. В момент, когда содержимое всех табов спрятано — контента на странице становится меньше и браузер прокручивает страницу вверх. Когда новый таб появляется — скрол остается на той же странице.

    Решение — не прятать все табы, а только ненужные:

    .parents('div.section').find('div.box').eq($(this).index()).fadeIn(150).siblings().hide();
    
  7. 7

    Если кому интересно — ещё одно простое решение для перехода к нужному табу по клику на стороннем элементе.

    $('[data-tab-target]').click(function(e) {
    		$("html, body").animate({scrollTop:$('#'+$(this).data('tab-target')).offset().top-50}, 500); //прокручиваем страницу чуть выше положения цели
    		$('#'+$(this).data('tab-target')).trigger('click');
    		return false;
    	});
    <span data-tab-target="tab-2">перейти к табу #tab-2</span>

    у

    <div class="section">
     <ul class="tabs">
     <li class="current">1-я вкладка</li>
     <li id="tab-2">2-я вкладка</li>
     </ul>
     <div class="box visible">
     Содержимое первого блока
     </div>
     <div class="box">
     Содержимое второго блока
     </div>
    </div><!-- .section -->
  8. 8

    Вот код, который это делает (доработан 4-й пример):

    (function($) {
    $(function() {
    
    	$('ul.tabs__caption').on('click', 'li:not(.active)', function() {
    		$(this)
    			.addClass('active').siblings().removeClass('active')
    			.closest('div.tabs').find('div.tabs__content').removeClass('active').eq($(this).index()).addClass('active');
    	});
    
    	var tabIndex = window.location.hash.replace('#tab','')-1;
    	if (tabIndex != -1) {
    		$('ul.tabs__caption li').eq(tabIndex).click();
    		$('html, body').animate({scrollTop: $('div.tabs__content').eq(tabIndex).offset().top - 50}, 700);
    	}
    
    	$('a[href*=#tab]').click(function() {
    		var tabIndex = $(this).attr('href').replace(/(.*)#tab/, '')-1;
    		$('ul.tabs__caption li').eq(tabIndex).click();
    		$('html, body').animate({scrollTop: $('div.tabs__content').eq(tabIndex).offset().top - 50}, 700);
    	});
    
    });
    })(jQuery);

    Число 50 (в двух местах) — это отступ между блоком и верхней границей окна браузера после прокрутки к блоку. 700 — это скорость прокрутки, в данном случае 0,7 секунды.

Ваш комментарий