Fixed #1446 and #1486 - Improve Tabview component

pull/1533/head
mertsincan 2021-08-31 09:46:25 +03:00
parent b9736729cd
commit 0704975c15
1 changed files with 104 additions and 13 deletions

View File

@ -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>