When the created tab label exceeds the visible area of the page, it will automatically scroll a tab label distance, and you can click to scroll the tab label manually. See the GIF image for the effect. Effect preview GIF <template> <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> </div> </div> </template> <script> export default { 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) * Length of a single tab label element - 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}`, 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)) // Element actual width = element width + margin this.width = marginLeft + marginRight + tabs.children[0].children[0].offsetWidth /** * The following comment calculation method is used to understand the implementation logic**/ // // How many elements can be placed in the visible area = width of the visible area / actual width of the sub-element // let num = tabs.offsetWidth / this.width // // The width of the visible part of the obscured tab element = the width of the visible area - (actual width of the child element * num converted to an integer) // this.unoccupied = tabs.offsetWidth - (this.width * parseInt(num)) //Finally simplified to remainder (the result is the same as the calculation above) 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 } } } }, /** * Shift to the right**/ next() { // scrollWidth is not accurate // 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 // Visible area < scrolling area (scrolling area can only be moved if it is larger than the visible area) // Moving distance + visible area = scroll area width (the last width, the actual width when clicked) < scroll areaif (dom.clientWidth < totalWidth && this.moveX + dom.clientWidth < totalWidth) { // this.moveX is 0 minus the width of the unoccupied space this.moveX += this.moveX ? this.width : this.width - this.unoccupied this.translateX(this.moveX) } }) }, /** * Left offset**/ 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)` } } } </script> <style lang="scss" scoped> .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%; } } </style> This is the end of this article about Vue's implementation of tab tags (tabs exceed automatic scrolling). For more relevant Vue tab tag content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future! You may also be interested in:
|
<<: Linux common commands chmod to modify file permissions 777 and 754
>>: MySQL Server IO 100% Analysis and Optimization Solution
Many people have encountered this error when star...
Because using group by in MySQL always results in...
Preface In order to follow the conventional WEB l...
This article example shares the specific code of ...
The idea of using token for login verification ...
Table of contents 1. What is a closure? 2. The ro...
Table of contents Cycle comparison usage Summariz...
Table of contents question: 1. Enable remote logi...
Table of contents JS obtains the .txt file conten...
HTML is a hybrid language used for publishing on ...
1. First enter the server's mysql to modify p...
Firewall A firewall is a set of rules. When a pac...
Linux file permissions First, let's check the...
There are four types of positioning in CSS, which...
Many tables in MySQL contain columns that can be ...