A Pen by Edward Lance Lorilla on CodePen.
Created
May 25, 2021 17:02
-
-
Save edwardlorilla/8184271ae61b29ba059066deb792ed7e to your computer and use it in GitHub Desktop.
jOBwOzM
This file contains hidden or 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
<div id="app"> | |
<div class="main-box"> | |
<button @click="add">Add</button> | |
<div class="main-box-tab"> | |
<i @click="previous"><<</i> | |
<i @click="next">>></i> | |
<div class="main-box-tab-content" ref="tabs"> | |
<div class="main-box-tab-roll"> | |
<div v-for="(item,index) in tabs" :key="index" | |
:class="{'tab-item-action':actionName === item.name ,'tab-item':actionName !== item.name}" | |
@click.stop="clickTab(item.name,index)"> | |
<span>{{item.meta.title}}</span> | |
<i class="el-icon-close" @click.stop="close(item.name)"></i> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="main-box-content"> | |
<div>{{actionName}}</div></b> | |
</div> | |
</div> | |
</div> |
This file contains hidden or 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
new Vue( { | |
name: "index", | |
data() { | |
return { | |
tabs: [], | |
moveX: 0, | |
count: 1, | |
unoccupied: 0, | |
tabsCount: 0, | |
actionName: 'test1' | |
} | |
}, | |
watch: { | |
actionName(val) { | |
let len = this.tabs.length | |
// If there is duplicate data, exit the subsequent function execution | |
for (let i = 0; i <len; i++) { | |
if (this.tabs[i].name === val) { | |
this.$nextTick(() => { | |
this.translateX((i + 1-this.tabsCount) * this.width-this.unoccupied) | |
}) | |
return | |
} | |
} | |
this.tabs.push({ | |
name: `test${this.count}`, | |
meta: { | |
title: `test${this.count}` | |
} | |
}) | |
this.$nextTick(() => { | |
// (How many tabs are there in total-the number of elements visible when not offset) * The length of a single tab tag element-the width of the visible part of the obscured tab element | |
this.translateX((this.tabs.length-this.tabsCount) * this.width-this.unoccupied) | |
}) | |
} | |
}, | |
mounted() { | |
this.tabs.push({ | |
name: `test${this.count}`, | |
content: 'lorem ipsum', | |
meta: { | |
title: `test${this.count}` | |
} | |
}) | |
this.$nextTick(() => { | |
let tabs = this.$refs.tabs | |
let getStyle = getComputedStyle(tabs.children[0].children[0], null) | |
let marginLeft = parseFloat(getStyle.marginLeft.substr(0, getStyle.marginLeft.length - 2)) | |
let marginRight = parseFloat(getStyle.marginRight.substr(0, getStyle.marginRight.length - 2)) | |
// The actual width of the element = the width of the element + margin | |
this.width = marginLeft + marginRight + tabs.children[0].children[0].offsetWidth | |
// The final reduction is to take the remainder (the number is the same as the above calculation) | |
this.unoccupied = tabs.offsetWidth% this.width | |
// Convert to integer | |
this.tabsCount = parseInt(tabs.offsetWidth / this.width) | |
}) | |
}, | |
methods: { | |
add() { | |
this.count++ | |
this.actionName = `test${this.count}` | |
}, | |
/** | |
* Switch tab page | |
**/ | |
clickTab(name) { | |
if (this.actionName !== name) { | |
this.actionName = name | |
} | |
}, | |
/** | |
* Close the tab page | |
**/ | |
close(name) { | |
let len = this.tabs.length | |
let jumpName = null | |
if (len > 1) { | |
for (let i = 0; i < len; i++) { | |
if (this.tabs[i].name === name) { | |
this.tabs.splice(i, 1) | |
jumpName = this.tabs[i ? i - 1 : 0].name | |
if (this.actionName !== jumpName && name === this.actionName) { | |
this.actionName = jumpName | |
} | |
this.$nextTick(() => { | |
this.previous() | |
}) | |
return | |
} | |
} | |
} | |
}, | |
/** | |
* Offset to the right | |
**/ | |
next() { | |
// scrollWidth acquisition is inaccurate | |
// Use this.width * this.tabs.length to calculate the total length | |
let totalWidth = this.width * this.tabs.length | |
this.$nextTick(() => { | |
let dom = this.$refs.tabs | |
// Viewable area <scrolling area (the scrolling area is larger than the visible area to move) | |
// Moving distance + visible area = width of scrolling area (the last width, when clicked is the actual width) <scrolling area | |
if (dom.clientWidth <totalWidth && this.moveX + dom.clientWidth <totalWidth) { | |
// this.moveX is 0 minus the width of the free space | |
this.moveX += this.moveX? this.width: this.width-this.unoccupied | |
this.translateX(this.moveX) | |
} | |
}) | |
}, | |
/** | |
* Offset to the left | |
**/ | |
previous() { | |
if (this.moveX> 0) { | |
this.moveX -= this.width | |
this.translateX(this.moveX) | |
} | |
}, | |
/** | |
* Start moving dom | |
**/ | |
translateX(x) { | |
this.moveX = x <0? 0: x | |
this.$refs.tabs.children[0].style.transform = `translateX(-${this.moveX}px)` | |
} | |
} | |
}).$mount("#app") |
This file contains hidden or 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
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script> |
This file contains hidden or 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
.main-box { | |
height: 500px; | |
width: 500px; | |
padding: 10px 20px 20px 20px; | |
.main-box-tab { | |
position: relative; | |
padding: 10px 20px; | |
overflow: hidden; | |
& > i { | |
position: absolute; | |
cursor: pointer; | |
bottom: 15px; | |
&:nth-child(1) { | |
left: 0; | |
} | |
&:nth-child(2) { | |
right: 0; | |
} | |
} | |
.main-box-tab-content { | |
overflow: hidden; | |
.main-box-tab-roll { | |
transition: transform .5s; | |
display: flex; | |
align-items: center; | |
div { | |
flex-shrink: 0; | |
cursor: pointer; | |
width: 130px; | |
height: 25px; | |
margin: 0 5px; | |
display: flex; | |
align-items: center; | |
justify-content: space-between; | |
span, i { | |
font-size: 12px; | |
} | |
span { | |
margin-left: 10px; | |
overflow: hidden; | |
white-space: nowrap; | |
text-overflow: ellipsis; | |
} | |
i { | |
margin-right: 10px; | |
} | |
} | |
} | |
} | |
.tab-item { | |
color: #cccccc; | |
background-color: rgba(255, 255, 255, .5); | |
border-radius: 0 1px 0 1px; | |
border: 1px solid #052141; | |
} | |
.tab-item-action { | |
color: #ffffff; | |
background: rgba(0, 180, 255, 0.8); | |
border-radius: 0 1px 0 1px; | |
border: 1px solid #1E2088; | |
} | |
} | |
.main-box-content { | |
height: calc(100% - 70px); | |
padding: 10px; | |
border: 1px saddlebrown solid; | |
background-size: 100% 100%; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment