parent
b9736729cd
commit
0704975c15
|
@ -1,14 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="p-tabview p-component">
|
<div :class="contentClasses">
|
||||||
<ul ref="nav" class="p-tabview-nav" role="tablist">
|
<div class="p-tabview-nav-container">
|
||||||
<li role="presentation" v-for="(tab, i) of tabs" :key="getKey(tab,i)" :class="[{'p-highlight': (d_activeIndex === i), 'p-disabled': isTabDisabled(tab)}]">
|
<button v-if="scrollable" :class="prevButtonClasses" :disabled="backwardIsDisabled" @click="navBackward" type="button" v-ripple>
|
||||||
<a role="tab" class="p-tabview-nav-link" @click="onTabClick($event, i)" @keydown="onTabKeydown($event, i)" :tabindex="isTabDisabled(tab) ? null : '0'" :aria-selected="d_activeIndex === i" v-ripple>
|
<span class="pi pi-chevron-left"></span>
|
||||||
<span class="p-tabview-title" v-if="tab.props && tab.props.header">{{tab.props.header}}</span>
|
</button>
|
||||||
<component :is="tab.children.header" v-if="tab.children && tab.children.header"></component>
|
<div ref="content" class="p-tabview-nav-content" @scroll="onScroll">
|
||||||
</a>
|
<ul ref="nav" class="p-tabview-nav" role="tablist">
|
||||||
</li>
|
<li role="presentation" v-for="(tab, i) of tabs" :key="getKey(tab,i)" :class="[{'p-highlight': (d_activeIndex === i), 'p-disabled': isTabDisabled(tab)}]">
|
||||||
<li ref="inkbar" class="p-tabview-ink-bar"></li>
|
<a role="tab" class="p-tabview-nav-link" @click="onTabClick($event, i)" @keydown="onTabKeydown($event, i)" :tabindex="isTabDisabled(tab) ? null : '0'" :aria-selected="d_activeIndex === i" v-ripple>
|
||||||
</ul>
|
<span class="p-tabview-title" v-if="tab.props && tab.props.header">{{tab.props.header}}</span>
|
||||||
|
<component :is="tab.children.header" v-if="tab.children && tab.children.header"></component>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li ref="inkbar" class="p-tabview-ink-bar"></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<button v-if="scrollable" :class="nextButtonClasses" :disabled="forwardIsDisabled" @click="navForward" type="button" v-ripple>
|
||||||
|
<span class="pi pi-chevron-right"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="p-tabview-panels">
|
<div class="p-tabview-panels">
|
||||||
<template v-for="(tab, i) of tabs" :key="getKey(tab,i)">
|
<template v-for="(tab, i) of tabs" :key="getKey(tab,i)">
|
||||||
<div class="p-tabview-panel" role="tabpanel" v-if="lazy ? (d_activeIndex === i) : true" v-show="lazy ? true: (d_activeIndex === i)">
|
<div class="p-tabview-panel" role="tabpanel" v-if="lazy ? (d_activeIndex === i) : true" v-show="lazy ? true: (d_activeIndex === i)">
|
||||||
|
@ -34,16 +44,24 @@ export default {
|
||||||
lazy: {
|
lazy: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
scrollable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
d_activeIndex: this.activeIndex
|
d_activeIndex: this.activeIndex,
|
||||||
|
backwardIsDisabled: true,
|
||||||
|
forwardIsDisabled: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
activeIndex(newValue) {
|
activeIndex(newValue) {
|
||||||
this.d_activeIndex = newValue;
|
this.d_activeIndex = newValue;
|
||||||
|
|
||||||
|
this.updateScrollBar(newValue);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
|
@ -62,6 +80,8 @@ export default {
|
||||||
originalEvent: event,
|
originalEvent: event,
|
||||||
index: i
|
index: i
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.updateScrollBar(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('tab-click', {
|
this.$emit('tab-click', {
|
||||||
|
@ -79,6 +99,18 @@ export default {
|
||||||
this.$refs.inkbar.style.width = DomHandler.getWidth(tabHeader) + 'px';
|
this.$refs.inkbar.style.width = DomHandler.getWidth(tabHeader) + 'px';
|
||||||
this.$refs.inkbar.style.left = DomHandler.getOffset(tabHeader).left - DomHandler.getOffset(this.$refs.nav).left + 'px';
|
this.$refs.inkbar.style.left = DomHandler.getOffset(tabHeader).left - DomHandler.getOffset(this.$refs.nav).left + 'px';
|
||||||
},
|
},
|
||||||
|
updateScrollBar(index) {
|
||||||
|
let tabHeader = this.$refs.nav.children[index];
|
||||||
|
tabHeader.scrollIntoView(false);
|
||||||
|
},
|
||||||
|
updateButtonState() {
|
||||||
|
const content = this.$refs.content;
|
||||||
|
const { scrollLeft, scrollWidth } = content;
|
||||||
|
const width = DomHandler.getWidth(content);
|
||||||
|
|
||||||
|
this.backwardIsDisabled = scrollLeft === 0;
|
||||||
|
this.forwardIsDisabled = scrollLeft === scrollWidth - width;
|
||||||
|
},
|
||||||
getKey(tab, i) {
|
getKey(tab, i) {
|
||||||
return (tab.props && tab.props.header) ? tab.props.header : i;
|
return (tab.props && tab.props.header) ? tab.props.header : i;
|
||||||
},
|
},
|
||||||
|
@ -87,9 +119,37 @@ export default {
|
||||||
},
|
},
|
||||||
isTabPanel(child) {
|
isTabPanel(child) {
|
||||||
return child.type.name === 'TabPanel'
|
return child.type.name === 'TabPanel'
|
||||||
|
},
|
||||||
|
onScroll(event) {
|
||||||
|
this.scrollable && this.updateButtonState();
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
navBackward() {
|
||||||
|
const content = this.$refs.content;
|
||||||
|
const width = DomHandler.getWidth(content);
|
||||||
|
const pos = content.scrollLeft - width;
|
||||||
|
content.scrollLeft = pos <= 0 ? 0 : pos;
|
||||||
|
},
|
||||||
|
navForward() {
|
||||||
|
const content = this.$refs.content;
|
||||||
|
const width = DomHandler.getWidth(content);
|
||||||
|
const pos = content.scrollLeft + width;
|
||||||
|
const lastPos = content.scrollWidth - width;
|
||||||
|
|
||||||
|
content.scrollLeft = pos >= lastPos ? lastPos : pos;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
contentClasses() {
|
||||||
|
return ['p-tabview p-component', {'p-tabview-scrollable': this.scrollable}];
|
||||||
|
},
|
||||||
|
prevButtonClasses() {
|
||||||
|
return ['p-tabview-nav-prev p-tabview-nav-btn p-link', {'p-disabled': this.backwardIsDisabled}]
|
||||||
|
},
|
||||||
|
nextButtonClasses() {
|
||||||
|
return ['p-tabview-nav-next p-tabview-nav-btn p-link', {'p-disabled': this.forwardIsDisabled}]
|
||||||
|
},
|
||||||
tabs() {
|
tabs() {
|
||||||
const tabs = []
|
const tabs = []
|
||||||
this.$slots.default().forEach(child => {
|
this.$slots.default().forEach(child => {
|
||||||
|
@ -106,7 +166,7 @@ export default {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return tabs;
|
return tabs;
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
'ripple': Ripple
|
'ripple': Ripple
|
||||||
|
@ -115,12 +175,23 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.p-tabview-nav-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tabview-nav-content {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
.p-tabview-nav {
|
.p-tabview-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
flex-wrap: wrap;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-tabview-nav-link {
|
.p-tabview-nav-link {
|
||||||
|
@ -144,5 +215,25 @@ export default {
|
||||||
|
|
||||||
.p-tabview-title {
|
.p-tabview-title {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tabview-nav-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
z-index: 2;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tabview-nav-prev {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tabview-nav-next {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tabview-nav-content::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue