Tabs add scroll

This commit is contained in:
marxy 2017-10-20 16:30:44 +08:00
parent 2e8add2fb3
commit be3fbd2499
3 changed files with 161 additions and 6 deletions

View file

@ -70,7 +70,7 @@
<!--</script>-->
<template>
<!-- <template>
<Tabs type="card" closable @on-tab-remove="handleTabRemove">
<TabPane label="标签一" v-if="tab0">标签一的内容</TabPane>
<TabPane label="标签二" v-if="tab1">标签二的内容</TabPane>
@ -92,4 +92,41 @@
}
}
}
</script> -->
<template>
<div>
<Button type="ghost" @click="toFirst" size="small">to first</Button>
<Button type="ghost" @click="toLast" size="small">to last</Button>
<Tabs type="card" :animated="animated" v-model="activeTab">
<TabPane v-for="tab in tabs" :key="tab" :label="'标签' + tab" :name="tab+''" closable>标签{{ tab }}</TabPane>
<div slot="extra">
<Button type="ghost" @click="handleTabsAdd" size="small">增加</Button>
</div>
</Tabs>
</div>
</template>
<script>
export default {
data () {
return {
tabs: 2,
activeTab:"2",
animated:true
}
},
methods: {
handleTabsAdd () {
this.tabs ++;
this.activeTab = this.tabs + '';
},
toFirst () {
this.activeTab = '1';
},
toLast () {
this.activeTab = this.tabs+'';
}
}
}
</script>

View file

@ -1,10 +1,13 @@
<template>
<div :class="classes">
<div :class="[prefixCls + '-bar']">
<div :class="[prefixCls + '-nav-right']" v-if="showSlot"><slot name="extra"></slot></div>
<div :class="[prefixCls + '-nav-container']">
<div :class="[prefixCls + '-nav-wrap']">
<div :class="[prefixCls + '-nav-scroll']">
<div :class="[prefixCls + '-nav']" ref="nav">
<div ref="navWrap" :class="[prefixCls + '-nav-wrap', scrollable ? prefixCls + '-nav-scrollable' : '']" >
<span :class="[prefixCls + '-nav-prev', scrollable ? '' : prefixCls + '-nav-scroll-disabled']" @click="scrollPrev"><Icon type="chevron-left"></Icon></span>
<span :class="[prefixCls + '-nav-next', scrollable ? '' : prefixCls + '-nav-scroll-disabled']" @click="scrollNext"><Icon type="chevron-right"></Icon></span>
<div ref="navScroll" :class="[prefixCls + '-nav-scroll']">
<div ref="nav" :class="[prefixCls + '-nav']" class="nav-text" :style="navStyle">
<div :class="barClasses" :style="barStyle"></div>
<div :class="tabCls(item)" v-for="(item, index) in navList" @click="handleChange(index)">
<Icon v-if="item.icon !== ''" :type="item.icon"></Icon>
@ -13,7 +16,6 @@
<Icon v-if="showClose(item)" type="ios-close-empty" @click.native.stop="handleRemove(index)"></Icon>
</div>
</div>
<div :class="[prefixCls + '-nav-right']" v-if="showSlot"><slot name="extra"></slot></div>
</div>
</div>
</div>
@ -26,6 +28,7 @@
import Render from '../base/render';
import { oneOf } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
import elementResizeDetectorMaker from 'element-resize-detector';
const prefixCls = 'ivu-tabs';
@ -65,7 +68,11 @@
barWidth: 0,
barOffset: 0,
activeKey: this.value,
showSlot: false
showSlot: false,
navStyle:{
transform: ''
},
scrollable:false
};
},
computed: {
@ -163,6 +170,7 @@
} else {
this.barOffset = 0;
}
this.updateNavScroll();
});
},
updateStatus () {
@ -222,6 +230,85 @@
} else {
return false;
}
},
scrollPrev() {
const containerWidth = this.$refs.navScroll.offsetWidth;
const currentOffset = this.getCurrentScrollOffset();
if (!currentOffset) return;
let newOffset = currentOffset > containerWidth
? currentOffset - containerWidth
: 0;
this.setOffset(newOffset);
},
scrollNext() {
const navWidth = this.$refs.nav.offsetWidth;
const containerWidth = this.$refs.navScroll.offsetWidth;
const currentOffset = this.getCurrentScrollOffset();
if (navWidth - currentOffset <= containerWidth) return;
let newOffset = navWidth - currentOffset > containerWidth * 2
? currentOffset + containerWidth
: (navWidth - containerWidth);
this.setOffset(newOffset);
},
getCurrentScrollOffset() {
const { navStyle } = this;
return navStyle.transform
? Number(navStyle.transform.match(/translateX\(-(\d+(\.\d+)*)px\)/)[1])
: 0;
},
setOffset(value) {
this.navStyle.transform = `translateX(-${value}px)`;
},
scrollToActiveTab() {
if (!this.scrollable) return;
const nav = this.$refs.nav;
const activeTab = this.$el.querySelector(`.${prefixCls}-tab-active`);
if(!activeTab) return;
const navScroll = this.$refs.navScroll;
const activeTabBounding = activeTab.getBoundingClientRect();
const navScrollBounding = navScroll.getBoundingClientRect();
const navBounding = nav.getBoundingClientRect();
const currentOffset = this.getCurrentScrollOffset();
let newOffset = currentOffset;
if (navBounding.right < navScrollBounding.right) {
newOffset = nav.offsetWidth - navScrollBounding.width;
}
if (activeTabBounding.left < navScrollBounding.left) {
newOffset = currentOffset - (navScrollBounding.left - activeTabBounding.left);
}else if (activeTabBounding.right > navScrollBounding.right) {
newOffset = currentOffset + activeTabBounding.right - navScrollBounding.right;
}
if(currentOffset !== newOffset){
this.setOffset(Math.max(newOffset, 0));
}
},
updateNavScroll(){
const navWidth = this.$refs.nav.offsetWidth;
const containerWidth = this.$refs.navScroll.offsetWidth;
const currentOffset = this.getCurrentScrollOffset();
if (containerWidth < navWidth) {
this.scrollable = true;
if (navWidth - currentOffset < containerWidth) {
this.setOffset(navWidth - containerWidth);
}
} else {
this.scrollable = false;
if (currentOffset > 0) {
this.setOffset(0);
}
}
},
handleResize(){
this.updateNavScroll();
}
},
watch: {
@ -232,10 +319,18 @@
this.updateBar();
this.updateStatus();
this.broadcast('Table', 'on-visible-change', true);
this.$nextTick(function(){
this.scrollToActiveTab();
});
}
},
mounted () {
this.showSlot = this.$slots.extra !== undefined;
this.observer = elementResizeDetectorMaker();
this.observer.listenTo(this.$refs.navWrap, this.handleResize);
},
beforeDestroy() {
this.observer.removeListener(this.$refs.navWrap, this.handleResize);
}
};
</script>

View file

@ -56,6 +56,29 @@
&-nav-right{
float: right;
margin-left: 5px;
}
&-nav-prev{
position:absolute;
line-height: 32px;
cursor: pointer;
left:0;
}
&-nav-next{
position:absolute;
line-height: 32px;
cursor: pointer;
right:0;
}
&-nav-scrollable{
padding: 0 12px;
}
&-nav-scroll-disabled{
display: none;
}
&-nav {