我想用一个选项卡导航来控制两个不同的选项卡内容。
在 Bootstra 3 中,我有一个用逗号分隔数据目标的解决方案(如本例所示:https://stackoverflow.com/a/19719859/1788961)。
但是在 Bootsrap 4 中,这种方式不再适用于选项卡。
折叠组件可以与多个目标一起使用,但我无法将其用于选项卡:https://getbootstrap.com/docs/4.0/components/collapse/#multiple-targets
还有其他方法可以做到这一点吗?
这是我的代码:
<div class="B">
<div class="container">
<div class="tab-content" id="ueberTabA">
<div class="tab-pane fade" id="panel_a_first" role="tabpanel" aria-labelledby="first-tab">
A First
</div>
<div class="tab-pane fade show active" id="panel_a_second" role="tabpanel" aria-labelledby="second-tab">
A Second
</div>
<div class="tab-pane fade" id="panel_a_third" role="tabpanel" aria-labelledby="third-tab">
A Third
</div>
</div>
</div>
</div>
<div class="container">
<ul class="nav nav-tabs" id="ueberTab" role="tablist">
<li class="nav-item"><a class="nav-link" id="first-tab" data-target="#panel_b_first, #panel_a_first" data-toggle="tab" href="#first" role="tab" aria-controls="first" aria-selected="false">first</a></li>
<li class="nav-item"><a class="nav-link active" id="second-tab" data-target="#panel_b_second, #panel_a_second" data-toggle="tab" href="#second" role="tab" aria-controls="second" aria-selected="true">second</a></li>
<li class="nav-item"><a class="nav-link" id="third-tab" data-target="#panel_b_thrid, #panel_a_third" data-toggle="tab" href="#third" role="tab" aria-controls="third" aria-selected="false">Unser third</a></li>
</ul>
<div class="tab-content" id="ueberTabB">
<div class="tab-pane fade" id="panel_b_first" role="tabpanel" aria-labelledby="first-tab">
B First
</div>
<div class="tab-pane fade show active" id="panel_b_second" role="tabpanel" aria-labelledby="second-tab">
B Second
</div>
<div class="tab-pane fade" id="panel_b_thrid" role="tabpanel" aria-labelledby="third-tab">
B Third
</div>
</div>
</div>
Bootstrap 5(2021 年更新)
这对于“开箱即用”的选项卡来说是不可能的。然而,JS 可以用来显示辅助选项卡窗格...
document.querySelectorAll('button[data-bs-toggle="tab"]').forEach((t,i)=>{
t.addEventListener('show.bs.tab', function (e) {
let targetClass = t.dataset.bsTarget
var pane = document.querySelector('#secondTabContent '+targetClass)
var sibling = document.querySelector('#secondTabContent .tab-pane.active')
// hide 2nd pane sibling
sibling.classList.remove('show')
sibling.classList.remove('active')
// show 2nd pane
pane.classList.add('show')
pane.classList.add('active')
})
})
Bootstrap 4(原始答案)
这在 Bootstrap 4.0.0 中是不可能的。目前这是一个悬而未决的问题,也是 Bootstrap 4.1 的一个可能的“想法”。
我实际上已经找到了一种方法来完成这项工作。这不是最漂亮的解决方案,但它确实可以完成任务。
您需要执行以下操作:
$(document).on('click', '#ueberTab a', function(e) {
otherTabs = $(this).attr('data-secondary').split(',');
for(i= 0; i<otherTabs.length;i++) {
nav = $('<ul class="nav d-none" id="tmpNav"></ul>');
nav.append('<li class="nav-item"><a href="#" data-toggle="tab" data-target="' + otherTabs[i] + '">nav</a></li>"');
nav.find('a').tab('show');
}
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script><div class="B">
<div class="container">
<div class="tab-content" id="ueberTabA">
<div class="tab-pane fade" id="panel_a_first" role="tabpanel" aria-labelledby="first-tab">
A First
</div>
<div class="tab-pane fade show active" id="panel_a_second" role="tabpanel" aria-labelledby="second-tab">
A Second
</div>
<div class="tab-pane fade" id="panel_a_third" role="tabpanel" aria-labelledby="third-tab">
A Third
</div>
</div>
</div>
</div>
<div class="container">
<ul class="nav nav-tabs" id="ueberTab" role="tablist">
<li class="nav-item"><a class="nav-link" id="first-tab" data-target="#panel_b_first" data-secondary="#panel_a_first" data-toggle="tab" href="#first" role="tab" aria-controls="first" aria-selected="false">first</a></li>
<li class="nav-item"><a class="nav-link active" id="second-tab" data-target="#panel_b_second" data-secondary="#panel_a_second" data-toggle="tab" href="#second" role="tab" aria-controls="second" aria-selected="true">second</a></li>
<li class="nav-item"><a class="nav-link" id="third-tab" data-target="#panel_b_thrid" data-secondary="#panel_a_third" data-toggle="tab" href="#third" role="tab" aria-controls="third" aria-selected="false">Unser third</a></li>
</ul>
<div class="tab-content" id="ueberTabB">
<div class="tab-pane fade" id="panel_b_first" role="tabpanel" aria-labelledby="first-tab">
B First
</div>
<div class="tab-pane fade show active" id="panel_b_second" role="tabpanel" aria-labelledby="second-tab">
B Second
</div>
<div class="tab-pane fade" id="panel_b_thrid" role="tabpanel" aria-labelledby="third-tab">
B Third
</div>
</div>
</div>
我想值得将 Carol Skelly 的答案 扩大到超过 2 个目标选项卡面板,并保持内置隐藏/显示动画正常工作。 BS 5 仅公开淡入淡出动画,所以让我们为其编写一个概念证明。
此外,BS 5 提供了一个带有导航链接的展示柜,如果您需要更复杂的布局,您可以删除它。
所以这是一个具有最小标记的概念证明:
/**
* Allow a bootstrap single nav tab to target multiple tab panels
*/
document.querySelectorAll( '[data-bs-toggle="tab"][data-bs-target]' ).forEach( ( navTab ) => {
const targetPanes = document.querySelectorAll( navTab.dataset.bsTarget )
if( targetPanes.length > 1 ) {
navTab.addEventListener( 'show.bs.tab', ( e ) => {
const activeNav = navTab.closest( '[role="tablist"]' ).querySelector( '.active[role="tab"]' )
const activePanes = document.querySelectorAll( activeNav.dataset.bsTarget )
// Hide other panes
activePanes.forEach( ( activePane ) => {
// Ensure selector targets only tab panels
if( activePane.matches( '[role="tabpanel"]' ) ) {
const transProperty = activePane.classList.contains( 'fade' ) ? 'opacity' : null
const outTransDuration = transProperty ? utils.toMilliseconds( utils.getComputedTransitions( activePane, '', transProperty ).duration ) : 0
// Remove class making pane visible
activePane.classList.remove( 'show' )
// Wait for transition...
setTimeout( () => {
// Then hide pane
activePane.classList.remove( 'active' )
targetPanes.forEach( ( targetPane ) => {
// Ensure selector targets only tab panels
if( targetPane.matches( '[role="tabpanel"]' ) ) {
const transProperty = targetPane.classList.contains( 'fade' ) ? 'opacity' : null
const inTransDuration = transProperty ? utils.toMilliseconds( utils.getComputedTransitions( targetPane, '', transProperty ).duration ) : 0
// Show pane
targetPane.classList.add( 'active' )
// Can't figure why, but this ensures animation of target panes beyond first lasts as long as animation of first
setTimeout( () => {
targetPane.classList.add( 'show' )
}, 0 )
}
} )
}, outTransDuration )
}
} )
} )
}
} )
/**
* Utils to get transition duration of a CSS property
*/
const utils = {
getComputedTransitions: ( elem, pseudo, property ) => {
const computedStyles = window.getComputedStyle( elem, pseudo )
const delays = computedStyles.getPropertyValue( 'transition-delay' ).split( ', ' )
const durations = computedStyles.getPropertyValue( 'transition-duration' ).split( ', ' )
const properties = computedStyles.getPropertyValue( 'transition-property' ).split( ', ' )
const timingFunctions = computedStyles.getPropertyValue( 'transition-timing-function' ).split( ', ' )
let transitions = {}
for( let i in properties ) {
transitions[properties[i] || 'all'] = {
duration: durations[i],
delay: delays[i],
timingFunction: timingFunctions[i],
}
}
if( property ) {
return transitions[property] ? transitions[property] : transitions['all']
}
return transitions
},
toMilliseconds: ( string ) => {
if( string.match( /^[0-9.]+s$/g ) ) {
return parseFloat( string ) * 1000
}
if( string.match( /^[0-9.]+ms$/g ) ) {
return parseFloat( string )
}
return string
}
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<div role="tablist">
<button type="button" class="active" data-bs-toggle="tab" data-bs-target=".pane-first" role="tab" aria-controls="pane-first" aria-selected="true">Tab first</button>
<button type="button" data-bs-toggle="tab" data-bs-target=".pane-second" role="tab" aria-controls="pane-first" aria-selected="false">Tab second</button>
</div>
...
<div class="tab-content">
<div class="tab-pane fade pane-first active show" role="tabpanel">Block 1, pane first</div>
<div class="tab-pane fade pane-second" role="tabpanel">Block 1, pane second</div>
</div>
...
<div class="tab-content">
<div class="tab-pane fade pane-first active show" role="tabpanel">Block 2, pane first</div>
<div class="tab-pane fade pane-second" role="tabpanel">Block 2, pane second</div>
</div>
淡入淡出过渡并不是真正同步的。我猜本地 BS 功能会在块 1 选项卡面板切换时产生干扰。