Last active
August 28, 2019 20:11
-
-
Save katerlouis/e57774ace94d03a92608618fb4040f17 to your computer and use it in GitHub Desktop.
vue tabs infinite loop problem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="cfg-tabs"> | |
<div class="cfg-tabs-links"> | |
<button :ref="'link'+i" class="cfg-tabs-link" @click="selectTab($event, tab)" v-for="(tab, i) in tabs" :key="i"> | |
{{ tab.title }} | |
</button> | |
<div class="cfg-tabs-active-indicator" :style="activeIndicatorStyles"></div> | |
</div> | |
<div class="cfg-tab-content"> | |
<slot></slot> | |
</div> | |
</div> | |
</template> | |
<script> | |
/** | |
* 2Do: | |
* – select zero tab when no `selected` tag` is provided | |
*/ | |
import { TweenMax } from "gsap" | |
import $ from "jquery" | |
export default { | |
name: 'Tabs', | |
components: { | |
Typography: require('./Typography').default, | |
}, | |
data () { | |
return { | |
tabs: [], | |
activeIndicatorStyles: { | |
// 2do: set this data on created and get it from real css | |
left: "73px", | |
width: "50px", | |
} | |
} | |
}, | |
created() { | |
// this.$children is not working, and even if it would | |
// the docs state you can't be sure $children will represent | |
// the correct dom order, so it's unreliable as the single source of truth | |
// this.tabs = this.$slots.default | |
this.tabs = this.$children | |
// set active index based on a prop | |
// in case the user defines a different active tab | |
// | |
// position activeindicator based on active tab | |
}, | |
mounted() { | |
// some internal stuff in vue needs to happen | |
// before we can fully use `this.$refs` – | |
// the weird part is, that if you console.log(this.$refs) | |
// it is actually undefined, but chrome will fill it in | |
// as soon as it's available... that's why it seems like | |
// `this.$refs` is availalbe... when it actually is not | |
// so when you try to access a specific ref, javascript throws an error | |
this.$nextTick(() => { | |
// find first item where selected prop is true | |
const getActiveTab = (tab) => tab.selected === true | |
const activeTab = this.tabs.find(getActiveTab) | |
const activeTabIndex = this.tabs.findIndex(getActiveTab) | |
const activeTabLinkEl = $(this.$refs["link"+activeTabIndex]) | |
const activeTabLinkPosition = $(activeTabLinkEl).position() | |
const activeTabLinkWidth = $(activeTabLinkEl).outerWidth() | |
// show active tab content | |
this.tabs.forEach(tab => { | |
tab.isActive = activeTab.title === tab.title | |
}) | |
TweenMax.fromTo(this.activeIndicatorStyles, .3, { | |
left: activeTabLinkPosition.left + activeTabLinkWidth / 2, | |
width: 0 | |
}, { | |
left: activeTabLinkPosition.left + "px", | |
width: activeTabLinkWidth + "px", | |
ease: Back.easeOut.config(1.1), | |
delay: 0, | |
}) | |
}) | |
}, | |
methods: { | |
selectTab($event, selectedTab) { | |
this.tabs.forEach(tab => { | |
tab.isActive = selectedTab.title === tab.title | |
}) | |
this.positionActiveIndicator($event.target) | |
// 2do: | |
// animate the active indicator | |
// animate height change and maybe transition between old and new tab.. which.. well.. damn we can't access the slots so easily:F | |
}, | |
positionActiveIndicator(clickedElement) { | |
const position = $(clickedElement).position() | |
TweenMax.to(this.activeIndicatorStyles, .3, { | |
left: position.left + "px", | |
width: $(clickedElement).outerWidth() + "px", | |
// ease: Back.easeOut.config(1.3), | |
ease: Power3.easeOut, | |
}) | |
} | |
}, | |
} | |
</script> | |
<style lang="css" scoped> | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment