mirror of
https://github.com/Hopiu/vue-material.git
synced 2026-05-18 20:21:07 +00:00
recreate tabs
This commit is contained in:
parent
f27d56fc09
commit
8eb59ab163
6 changed files with 140 additions and 566 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<page-content page-title="Components - Tabs">
|
||||
<!-- <docs-component>
|
||||
<docs-component>
|
||||
<div slot="description">
|
||||
<p>Tabs enable content organization at a high level, such as switching between views, data sets, or functional aspects of an app.</p>
|
||||
<p>The following classes can be applied to change the color palette:</p>
|
||||
|
|
@ -123,7 +123,7 @@
|
|||
<div slot="example">
|
||||
<example-box card-title="Default">
|
||||
<div slot="demo">
|
||||
<md-tabs>
|
||||
<md-tabs :md-dynamic-height="false">
|
||||
<md-tab id="movies" md-label="Movies">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
|
@ -167,19 +167,23 @@
|
|||
</div>
|
||||
</example-box>
|
||||
|
||||
<example-box card-title="Fixed with only icons">
|
||||
<example-box card-title="Fixed">
|
||||
<div slot="demo">
|
||||
<md-tabs md-fixed>
|
||||
<md-tab md-icon="phone">
|
||||
<md-tabs :md-dynamic-height="false" md-fixed>
|
||||
<md-tab id="movies" md-label="Movies">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab md-icon="favorite">
|
||||
<md-tab id="music" md-label="Music">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab md-icon="near_me">
|
||||
<md-tab id="books" md-label="Books">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="pictures" md-label="Pictures">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
|
|
@ -188,16 +192,20 @@
|
|||
<div slot="code">
|
||||
<code-block lang="xml">
|
||||
<md-tabs md-fixed>
|
||||
<md-tab md-icon="phone">
|
||||
<md-tab id="movies" md-label="Movies">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab md-icon="favorite">
|
||||
<md-tab id="music" md-label="Music">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab md-icon="near_me">
|
||||
<md-tab id="books" md-label="Books">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="pictures" md-label="Pictures">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
|
|
@ -207,7 +215,7 @@
|
|||
|
||||
<example-box card-title="Centered with Text and Icon">
|
||||
<div slot="demo">
|
||||
<md-tabs md-centered>
|
||||
<md-tabs :md-dynamic-height="false" md-centered>
|
||||
<md-tab md-label="Movies" md-icon="ondemand_video">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
|
@ -251,23 +259,19 @@
|
|||
</div>
|
||||
</example-box>
|
||||
|
||||
<example-box card-title="Aligned to the right">
|
||||
<example-box card-title="Aligned to the right with only icons">
|
||||
<div slot="demo">
|
||||
<md-tabs md-right>
|
||||
<md-tab id="movies" md-label="Movies">
|
||||
<md-tabs :md-dynamic-height="false" md-right>
|
||||
<md-tab md-icon="phone">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="music" md-label="Music">
|
||||
<md-tab md-icon="favorite">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="books" md-label="Books">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="pictures" md-label="Pictures">
|
||||
<md-tab md-icon="near_me">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
|
|
@ -276,233 +280,23 @@
|
|||
<div slot="code">
|
||||
<code-block lang="xml">
|
||||
<md-tabs md-right>
|
||||
<md-tab id="movies" md-label="Movies">
|
||||
<md-tab md-icon="phone">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="music" md-label="Music">
|
||||
<md-tab md-icon="favorite">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="books" md-label="Books">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="pictures" md-label="Pictures">
|
||||
<md-tab md-icon="near_me">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
</code-block>
|
||||
</div>
|
||||
</example-box>
|
||||
|
||||
<example-box card-title="Playground">
|
||||
<div slot="demo">
|
||||
<div class="playground">
|
||||
<md-subheader>Tabs Attributes</md-subheader>
|
||||
<md-checkbox id="fixed" v-model="playground.fixed">Fixed</md-checkbox>
|
||||
<md-checkbox id="centered" v-model="playground.centered">Centered</md-checkbox>
|
||||
<md-input-container>
|
||||
<label for="shadow">Shadow</label>
|
||||
<md-input type="number" id="shadow" v-model="playground.shadow" min="0" max="24"></md-input>
|
||||
</md-input-container>
|
||||
|
||||
<md-subheader>Theme</md-subheader>
|
||||
<md-radio v-model="playground.theme" id="theme1" name="theme" md-value="default">Default</md-radio>
|
||||
<md-radio v-model="playground.theme" id="theme2" name="theme" md-value="green">Green</md-radio>
|
||||
<md-radio v-model="playground.theme" id="theme3" name="theme" md-value="cyan">Cyan</md-radio>
|
||||
<md-radio v-model="playground.theme" id="theme4" name="theme" md-value="brown">Brown</md-radio>
|
||||
|
||||
<md-subheader>Colors</md-subheader>
|
||||
<md-radio v-model="playground.color" id="color1" name="color" md-value="0">Default</md-radio>
|
||||
<md-radio v-model="playground.color" id="color2" name="color" md-value="1">Accent</md-radio>
|
||||
<md-radio v-model="playground.color" id="color3" name="color" md-value="2">Warn</md-radio>
|
||||
<md-radio v-model="playground.color" id="color4" name="color" md-value="3">Transparent</md-radio>
|
||||
|
||||
<md-subheader>Second Tab</md-subheader>
|
||||
<md-checkbox id="disabled" v-model="playground.tabs[1].disabled">Disabled</md-checkbox>
|
||||
<md-checkbox id="active" v-model="playground.tabs[1].active">Active</md-checkbox>
|
||||
</div>
|
||||
|
||||
<md-tabs
|
||||
:class="{
|
||||
'md-accent': playground.color === '1',
|
||||
'md-warn': playground.color === '2',
|
||||
'md-transparent': playground.color === '3'
|
||||
}"
|
||||
:md-fixed="playground.fixed"
|
||||
:md-centered="playground.centered"
|
||||
:md-elevation="playground.shadow"
|
||||
v-md-theme="playground.theme">
|
||||
<md-tab v-for="(tab, index) in playground.tabs" :md-label="tab.label" :md-icon="tab.icon" :md-disabled="tab.disabled" :md-active="tab.active">
|
||||
<md-input-container>
|
||||
<label :for="'label' + index">Label</label>
|
||||
<md-input type="text" :id="'label' + index" v-model="tab.label"></md-input>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container>
|
||||
<label :for="'icon' + index">Icon</label>
|
||||
<md-input type="text" :id="'icon' + index" v-model="tab.icon"></md-input>
|
||||
</md-input-container>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
</div>
|
||||
|
||||
<div slot="code">
|
||||
<code-block lang="xml">
|
||||
<div class="playground">
|
||||
<md-subheader>Tabs Attributes</md-subheader>
|
||||
<md-checkbox id="fixed" v-model="playground.fixed">Fixed</md-checkbox>
|
||||
<md-checkbox id="centered" v-model="playground.centered">Centered</md-checkbox>
|
||||
<md-input-container>
|
||||
<label for="shadow">Shadow</label>
|
||||
<md-input type="number" id="shadow" v-model="playground.shadow" min="0" max="24"></md-input>
|
||||
</md-input-container>
|
||||
|
||||
<md-subheader>Theme</md-subheader>
|
||||
<md-radio v-model="playground.theme" id="theme1" name="theme" md-value="default">Default</md-radio>
|
||||
<md-radio v-model="playground.theme" id="theme2" name="theme" md-value="green">Green</md-radio>
|
||||
<md-radio v-model="playground.theme" id="theme3" name="theme" md-value="cyan">Cyan</md-radio>
|
||||
<md-radio v-model="playground.theme" id="theme4" name="theme" md-value="brown">Brown</md-radio>
|
||||
|
||||
<md-subheader>Colors</md-subheader>
|
||||
<md-radio v-model="playground.color" id="color1" name="color" md-value="0">Default</md-radio>
|
||||
<md-radio v-model="playground.color" id="color2" name="color" md-value="1">Accent</md-radio>
|
||||
<md-radio v-model="playground.color" id="color3" name="color" md-value="2">Warn</md-radio>
|
||||
<md-radio v-model="playground.color" id="color4" name="color" md-value="3">Transparent</md-radio>
|
||||
|
||||
<md-subheader>Second Tab</md-subheader>
|
||||
<md-checkbox id="disabled" v-model="playground.tabs[1].disabled">Disabled</md-checkbox>
|
||||
<md-checkbox id="active" v-model="playground.tabs[1].active">Active</md-checkbox>
|
||||
</div>
|
||||
|
||||
<md-tabs
|
||||
:class="{
|
||||
'md-accent': playground.color === '1',
|
||||
'md-warn': playground.color === '2',
|
||||
'md-transparent': playground.color === '3'
|
||||
}"
|
||||
:md-fixed="playground.fixed"
|
||||
:md-centered="playground.centered"
|
||||
:md-elevation="playground.shadow"
|
||||
v-md-theme="playground.theme">
|
||||
<md-tab v-for="(tab, index) in playground.tabs" :md-label="tab.label" :md-icon="tab.icon" :md-disabled="tab.disabled" :md-active="tab.active">
|
||||
<md-input-container>
|
||||
<label :for="'label' + index">Label</label>
|
||||
<md-input type="text" :id="'label' + index" v-model="tab.label"></md-input>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container>
|
||||
<label :for="'icon' + index">Icon</label>
|
||||
<md-input type="text" :id="'icon' + index" v-model="tab.icon"></md-input>
|
||||
</md-input-container>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
</code-block>
|
||||
|
||||
<code-block lang="javascript">
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
playground: {
|
||||
color: '3',
|
||||
fixed: true,
|
||||
centered: false,
|
||||
shadow: 0,
|
||||
theme: 'default',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Phone',
|
||||
icon: 'phone',
|
||||
active: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: 'Favorites',
|
||||
icon: 'favorite',
|
||||
active: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: 'Near me',
|
||||
icon: 'near_me',
|
||||
active: true,
|
||||
disabled: false
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
</code-block>
|
||||
</div>
|
||||
</example-box>
|
||||
</div>
|
||||
</docs-component> -->
|
||||
|
||||
<md-tabs>
|
||||
<md-tab id="tab-1" md-label="Test 1">
|
||||
<p>Optio, assumenda placeat laboriosam incidunt obcaecati nisi, ipsa earum rem cumque nesciunt iste animi recusandae! Nostrum vero quod consequuntur enim quo cum.</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="tab-2" md-label="Test 2">
|
||||
<p>Animi architecto blanditiis nihil aliquam nemo aperiam quo asperiores quam suscipit quae labore in, qui odit beatae assumenda, accusamus, ex sapiente fugit?</p>
|
||||
</md-tab>
|
||||
|
||||
<md-tab id="tab-3" md-label="Test 3">
|
||||
<p>Excepturi, blanditiis in a non ipsa. Praesentium atque maxime officia amet porro veritatis, vitae quisquam ex magni nisi sed. Asperiores, vel aut.</p>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
</docs-component>
|
||||
</page-content>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.playground {
|
||||
padding: 0 16px 16px;
|
||||
|
||||
.md-subheader {
|
||||
padding: 16px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
div.examples .demo-example .demo-example-body {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
playground: {
|
||||
color: '3',
|
||||
fixed: true,
|
||||
centered: false,
|
||||
shadow: 0,
|
||||
theme: 'default',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Phone',
|
||||
icon: 'phone',
|
||||
active: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: 'Favorites',
|
||||
icon: 'favorite',
|
||||
active: false,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
label: 'Near me',
|
||||
icon: 'near_me',
|
||||
active: true,
|
||||
disabled: false
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
<template>
|
||||
<div class="md-tab" :id="tabId" ref="tab">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
id: [String, Number],
|
||||
mdLabel: [String, Number],
|
||||
mdIcon: String,
|
||||
mdActive: Boolean,
|
||||
mdDisabled: Boolean
|
||||
},
|
||||
data() {
|
||||
let id;
|
||||
|
||||
if (!this.id) {
|
||||
id = 'tab-' + Math.random().toString(36).substr(2, 10);
|
||||
}
|
||||
|
||||
return {
|
||||
tabId: this.id || id
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
mdActive() {
|
||||
this.updateTabData();
|
||||
},
|
||||
mdDisabled() {
|
||||
this.updateTabData();
|
||||
},
|
||||
mdIcon() {
|
||||
this.updateTabData();
|
||||
},
|
||||
mdLabel() {
|
||||
this.updateTabData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateTabData() {
|
||||
this.$parent.updateTabData({
|
||||
id: this.tabId,
|
||||
label: this.mdLabel,
|
||||
icon: this.mdIcon,
|
||||
active: this.mdActive,
|
||||
disabled: this.mdDisabled,
|
||||
ref: this.$refs.tab
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.$parent.$el.classList.contains('md-tabs')) {
|
||||
this.$destroy();
|
||||
|
||||
throw new Error('You should wrap the md-tab in a md-tabs');
|
||||
}
|
||||
|
||||
this.$parent.registerTab({
|
||||
id: this.tabId,
|
||||
label: this.mdLabel,
|
||||
icon: this.mdIcon,
|
||||
active: this.mdActive,
|
||||
disabled: this.mdDisabled,
|
||||
ref: this.$refs.tab
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="md-tab" :id="tabId">
|
||||
<div class="md-tab" :id="tabId" :style="styles">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -19,9 +19,33 @@
|
|||
data() {
|
||||
return {
|
||||
mounted: false,
|
||||
tabId: this.id || 'tab-' + uniqueId()
|
||||
tabId: this.id || 'tab-' + uniqueId(),
|
||||
width: '0px',
|
||||
left: '0px'
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
mdActive() {
|
||||
this.updateTabData();
|
||||
},
|
||||
mdDisabled() {
|
||||
this.updateTabData();
|
||||
},
|
||||
mdIcon() {
|
||||
this.updateTabData();
|
||||
},
|
||||
mdLabel() {
|
||||
this.updateTabData();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
styles() {
|
||||
return {
|
||||
width: this.width,
|
||||
left: this.left
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTabData() {
|
||||
return {
|
||||
|
|
@ -29,8 +53,12 @@
|
|||
label: this.mdLabel,
|
||||
icon: this.mdIcon,
|
||||
active: this.mdActive,
|
||||
disabled: this.mdDisabled
|
||||
disabled: this.mdDisabled,
|
||||
ref: this
|
||||
};
|
||||
},
|
||||
updateTabData() {
|
||||
this.parentTabs.updateTab(this.getTabData());
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
|
|||
|
|
@ -1,211 +0,0 @@
|
|||
<template>
|
||||
<div class="md-tabs" :class="tabClasses">
|
||||
<md-whiteframe :md-elevation="elevation || 0">
|
||||
<div class="md-tabs-navigation" :class="navigationClasses">
|
||||
<button
|
||||
v-for="header in tabs"
|
||||
:key="header.id"
|
||||
type="button"
|
||||
class="md-tab-header"
|
||||
:class="getHeaderClass(header)"
|
||||
:disabled="header.disabled"
|
||||
@click="changeTab(header.id)"
|
||||
v-md-ink-ripple="header.disabled"
|
||||
ref="tabHeader">
|
||||
<div class="md-tab-header-container">
|
||||
<md-icon v-if="header.icon">{{ header.icon }}</md-icon>
|
||||
<span v-if="header.label">{{ header.label }}</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<span class="md-tab-indicator" :class="indicatorClass" ref="indicator"></span>
|
||||
</div>
|
||||
</md-whiteframe>
|
||||
|
||||
<div class="md-tabs-content" ref="tabContent">
|
||||
<div class="md-tabs-wrapper" ref="tabWrapper">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" src="./mdTabs.scss"></style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
mdFixed: Boolean,
|
||||
mdCentered: Boolean,
|
||||
mdRight: Boolean,
|
||||
mdDynamicHeight: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
mdElevation: [String, Number]
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasIcons: false,
|
||||
hasLabel: false,
|
||||
elevation: this.mdElevation,
|
||||
activeTab: '',
|
||||
activeTabNumber: 0,
|
||||
tabs: {}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
mdFixed() {
|
||||
let transitionCounter = 0;
|
||||
let transitionInterval = window.setInterval(() => {
|
||||
transitionCounter++;
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
this.calculateIndicatorPos(true);
|
||||
});
|
||||
|
||||
if (transitionCounter > 200) {
|
||||
window.clearInterval(transitionInterval);
|
||||
}
|
||||
}, 10);
|
||||
|
||||
this.recalculateAllTabsPos();
|
||||
},
|
||||
mdCentered() {
|
||||
this.recalculateAllTabsPos();
|
||||
},
|
||||
mdElevation() {
|
||||
this.elevation = this.mdElevation;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tabClasses() {
|
||||
return {
|
||||
'md-no-transition': !this.mdDynamicHeight
|
||||
};
|
||||
},
|
||||
navigationClasses() {
|
||||
return {
|
||||
'md-fixed': this.mdFixed,
|
||||
'md-right': !this.mdCentered && this.mdRight,
|
||||
'md-centered': this.mdCentered || this.mdFixed,
|
||||
'md-has-icon': this.hasIcons,
|
||||
'md-has-label': this.hasLabel
|
||||
};
|
||||
},
|
||||
indicatorClass() {
|
||||
let toLeft = this.lastIndicatorNumber > this.activeTabNumber;
|
||||
|
||||
this.lastIndicatorNumber = this.activeTabNumber;
|
||||
|
||||
return {
|
||||
'md-to-right': !toLeft,
|
||||
'md-to-left': toLeft
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getHeaderClass(header) {
|
||||
return {
|
||||
'md-active': this.activeTab === header.id,
|
||||
'md-disabled': header.disabled
|
||||
};
|
||||
},
|
||||
calculateIndicatorPos(recalculate) {
|
||||
let indicator = this.$refs.indicator;
|
||||
let tabsWidth = this.$el.offsetWidth;
|
||||
|
||||
if (recalculate) {
|
||||
indicator.classList.add('md-transition-off');
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
let activeTab = this.$refs.tabHeader[this.activeTabNumber];
|
||||
let left = activeTab.offsetLeft;
|
||||
let right = tabsWidth - left - activeTab.offsetWidth;
|
||||
|
||||
indicator.style.left = left + 'px';
|
||||
indicator.style.right = right + 'px';
|
||||
|
||||
if (recalculate) {
|
||||
window.setTimeout(() => {
|
||||
indicator.classList.remove('md-transition-off');
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
},
|
||||
calculateTabPos(ref, index) {
|
||||
this.$refs.tabWrapper.style.transform = 'translate3D(' + -this.$refs.tabContent.offsetWidth * this.activeTabNumber + 'px, 0, 0)';
|
||||
ref.style.width = this.$refs.tabContent.offsetWidth + 'px';
|
||||
ref.style.left = this.$refs.tabContent.offsetWidth * index + 'px';
|
||||
},
|
||||
setVisibleTab(ref) {
|
||||
this.$refs.tabContent.style.height = ref.offsetHeight + 'px';
|
||||
ref.classList.add('md-active');
|
||||
},
|
||||
changeTab(tabId) {
|
||||
let idList = Object.keys(this.tabs);
|
||||
let id = tabId || idList[0];
|
||||
let index = idList.indexOf(id);
|
||||
|
||||
this.tabs[this.activeTab || id].ref.classList.remove('md-active');
|
||||
this.activeTab = id;
|
||||
this.activeTabNumber = index;
|
||||
|
||||
this.$emit('change', index);
|
||||
|
||||
window.setTimeout(() => {
|
||||
this.calculateIndicatorPos();
|
||||
this.calculateTabPos(this.tabs[id].ref, index);
|
||||
this.setVisibleTab(this.tabs[id].ref);
|
||||
});
|
||||
},
|
||||
handleTabData(data) {
|
||||
let idList = Object.keys(this.tabs);
|
||||
let index = idList.indexOf(data.id);
|
||||
|
||||
this.hasIcons = !!data.icon;
|
||||
this.hasLabel = !!data.label;
|
||||
|
||||
if (!data.disabled && data.active) {
|
||||
this.changeTab(data.id);
|
||||
} else {
|
||||
this.changeTab(idList[index + 1]);
|
||||
}
|
||||
},
|
||||
registerTab(data) {
|
||||
this.tabs[data.id] = data;
|
||||
this.handleTabData(data);
|
||||
},
|
||||
updateTabData(data) {
|
||||
this.tabs[data.id] = data;
|
||||
this.handleTabData(data);
|
||||
this.recalculateAllTabsPos();
|
||||
this.$forceUpdate();
|
||||
},
|
||||
recalculateAllTabsPos(transitionOff) {
|
||||
if (typeof transitionOff === 'undefined') {
|
||||
transitionOff = true;
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
this.calculateIndicatorPos(!transitionOff);
|
||||
|
||||
Object.keys(this.tabs).forEach((tab, index) => {
|
||||
this.calculateTabPos(this.tabs[tab].ref, index);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.activeTab) {
|
||||
this.changeTab();
|
||||
}
|
||||
|
||||
window.addEventListener('resize', this.recalculateAllTabsPos);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.recalculateAllTabsPos);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -9,6 +9,16 @@ $tab-max-width: 264px;
|
|||
flex-flow: column;
|
||||
position: relative;
|
||||
|
||||
&.md-transition-off * {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
&.md-dynamic-height {
|
||||
.md-tabs-content {
|
||||
transition: height $swift-ease-out-duration $swift-ease-out-timing-function;
|
||||
}
|
||||
}
|
||||
|
||||
.md-tabs-navigation {
|
||||
height: 48px;
|
||||
min-height: 48px;
|
||||
|
|
@ -82,6 +92,10 @@ $tab-max-width: 264px;
|
|||
left: 0;
|
||||
transform: translate3D(0, 0, 0);
|
||||
|
||||
&.md-transition-off {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
&.md-to-right {
|
||||
transition: $swift-ease-out,
|
||||
left .3s $swift-ease-in-out-timing-function,
|
||||
|
|
@ -95,19 +109,14 @@ $tab-max-width: 264px;
|
|||
}
|
||||
}
|
||||
|
||||
.md-transition-off {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.md-tabs-content {
|
||||
width: 100%;
|
||||
//height: 0;
|
||||
height: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: height $swift-ease-out-duration $swift-ease-out-timing-function;
|
||||
}
|
||||
|
||||
/*.md-tabs-wrapper {
|
||||
.md-tabs-wrapper {
|
||||
width: 9999em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -116,28 +125,13 @@ $tab-max-width: 264px;
|
|||
left: 0;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: transform $swift-ease-out-duration $swift-ease-out-timing-function;
|
||||
}*/
|
||||
}
|
||||
|
||||
.md-tab {
|
||||
padding: 16px;
|
||||
/* position: absolute;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0; */
|
||||
pointer-events: none;
|
||||
//transform: translate3d(0, -100%, 0);
|
||||
transition: transform 0s $swift-ease-out-duration;
|
||||
|
||||
&.md-active {
|
||||
transform: translate3d(0, 0, 0);
|
||||
pointer-events: auto;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.md-tabs.md-no-transition {
|
||||
.md-tabs-content {
|
||||
transition: none !important;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
</div>
|
||||
</md-whiteframe>
|
||||
|
||||
<div class="md-tabs-content" ref="tabContent">
|
||||
<div class="md-tabs-wrapper" ref="tabWrapper">
|
||||
<div class="md-tabs-content" ref="tabContent" :style="{ height: contentHeight }">
|
||||
<div class="md-tabs-wrapper" :style="{ transform: `translate3D(-${contentWidth}, 0, 0)` }">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -33,8 +33,6 @@
|
|||
<style lang="scss" src="./mdTabs.scss"></style>
|
||||
|
||||
<script>
|
||||
import throttle from '../../core/utils/throttle';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
mdFixed: Boolean,
|
||||
|
|
@ -53,21 +51,26 @@
|
|||
tabList: {},
|
||||
activeTab: null,
|
||||
activeTabNumber: 0,
|
||||
transitionControl: null
|
||||
hasIcons: false,
|
||||
hasLabel: false,
|
||||
transitionControl: null,
|
||||
contentHeight: '0px',
|
||||
contentWidth: '0px'
|
||||
}),
|
||||
computed: {
|
||||
tabClasses() {
|
||||
return {
|
||||
'md-no-transition': !this.mdDynamicHeight
|
||||
'md-dynamic-height': this.mdDynamicHeight,
|
||||
'md-transition-off': this.transitionOff
|
||||
};
|
||||
},
|
||||
navigationClasses() {
|
||||
return {
|
||||
'md-has-icon': this.hasIcons,
|
||||
'md-has-label': this.hasLabel,
|
||||
'md-fixed': this.mdFixed,
|
||||
'md-right': !this.mdCentered && this.mdRight,
|
||||
'md-centered': this.mdCentered || this.mdFixed,
|
||||
'md-has-icon': this.hasIcons,
|
||||
'md-has-label': this.hasLabel
|
||||
'md-centered': this.mdCentered || this.mdFixed
|
||||
};
|
||||
},
|
||||
indicatorClasses() {
|
||||
|
|
@ -76,6 +79,7 @@
|
|||
this.lastIndicatorNumber = this.activeTabNumber;
|
||||
|
||||
return {
|
||||
'md-transition-off': this.transitionOff,
|
||||
'md-to-right': !toLeft,
|
||||
'md-to-left': toLeft
|
||||
};
|
||||
|
|
@ -93,14 +97,30 @@
|
|||
this.$forceUpdate();
|
||||
},
|
||||
unregisterTab(tabData) {
|
||||
console.log(tabData);
|
||||
delete this.tabList[tabData.id];
|
||||
},
|
||||
updateTab(tabData) {
|
||||
this.registerTab(tabData);
|
||||
|
||||
if (tabData.active) {
|
||||
if (!tabData.disabled) {
|
||||
this.setActiveTab(tabData);
|
||||
} else {
|
||||
let tabsIds = Object.keys(this.tabList);
|
||||
let targetIndex = tabsIds.indexOf(tabData.id) + 1;
|
||||
let target = tabsIds[targetIndex];
|
||||
|
||||
if (target) {
|
||||
this.setActiveTab(this.tabList[target]);
|
||||
} else {
|
||||
this.setActiveTab(this.tabList[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
observeElementChanges() {
|
||||
this.contentObserver = new MutationObserver(throttle(this.debounceTransition, 50));
|
||||
this.navigationObserver = new MutationObserver(throttle(this.debounceTransition, 50));
|
||||
this.contentObserver = new MutationObserver(this.calculateOnWatch);
|
||||
this.navigationObserver = new MutationObserver(this.calculateOnWatch);
|
||||
this.contentObserver.observe(this.$refs.tabContent, {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
|
|
@ -118,13 +138,6 @@
|
|||
|
||||
return idList.indexOf(id);
|
||||
},
|
||||
debounceTransition() {
|
||||
window.clearTimeout(this.transitionControl);
|
||||
this.transitionControl = window.setTimeout(() => {
|
||||
this.calculateIndicatorPos();
|
||||
this.$refs.indicator.classList.remove('md-transition-off');
|
||||
}, 200);
|
||||
},
|
||||
calculateIndicatorPos() {
|
||||
let tabsWidth = this.$el.offsetWidth;
|
||||
let activeTab = this.$refs.tabHeader[this.activeTabNumber];
|
||||
|
|
@ -134,13 +147,39 @@
|
|||
this.$refs.indicator.style.left = left + 'px';
|
||||
this.$refs.indicator.style.right = right + 'px';
|
||||
},
|
||||
calculateTabsWidthAndPosition() {
|
||||
const width = this.$el.offsetWidth;
|
||||
|
||||
this.contentWidth = width * this.activeTabNumber + 'px';
|
||||
|
||||
Object.values(this.tabList).forEach((tab, index) => {
|
||||
tab.ref.width = width + 'px';
|
||||
tab.ref.left = width * index + 'px';
|
||||
});
|
||||
},
|
||||
calculateContentHeight() {
|
||||
this.$nextTick(() => {
|
||||
let height = this.tabList[this.activeTab].ref.$el.offsetHeight;
|
||||
|
||||
this.contentHeight = height + 'px';
|
||||
});
|
||||
},
|
||||
calculatePosition() {
|
||||
window.requestAnimationFrame(() => {
|
||||
this.calculateIndicatorPos();
|
||||
this.calculateTabsWidthAndPosition();
|
||||
this.calculateContentHeight();
|
||||
});
|
||||
},
|
||||
onWindowResize() {
|
||||
this.$refs.indicator.classList.add('md-transition-off');
|
||||
debounceTransition() {
|
||||
window.clearTimeout(this.transitionControl);
|
||||
this.transitionControl = window.setTimeout(() => {
|
||||
this.calculatePosition();
|
||||
this.transitionOff = false;
|
||||
}, 200);
|
||||
},
|
||||
calculateOnWatch() {
|
||||
this.transitionOff = true;
|
||||
this.calculatePosition();
|
||||
this.debounceTransition();
|
||||
},
|
||||
|
|
@ -155,7 +194,7 @@
|
|||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.observeElementChanges();
|
||||
window.addEventListener('resize', this.onWindowResize);
|
||||
window.addEventListener('resize', this.calculateOnWatch);
|
||||
|
||||
if (!this.activeTab) {
|
||||
let firstTab = Object.keys(this.tabList)[0];
|
||||
|
|
@ -166,7 +205,7 @@
|
|||
},
|
||||
beforeDestroy() {
|
||||
this.contentObserver.disconnect();
|
||||
window.removeEventListener('resize', this.onWindowResize);
|
||||
window.removeEventListener('resize', this.calculateOnWatch);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue