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
I accidentally found that Vue.$set was invalid in...
console.log( [] == ![] ) // true console.log( {} ...
1. Install JDK 1.1 Check whether the current virt...
Table of contents Too long to read Component styl...
Worms replicate, as the name implies, by themselv...
Method 1: SET GLOBAL general_log = 'OFF';...
Designers need to understand psychology reading n...
There are many commands used in the system, so ho...
This article shares the specific code for using j...
This article shares the specific implementation c...
Here are two terminal split screen tools: screen ...
Recently, I have a project that requires using ifr...
In Google Chrome, after successful login, Google ...
CentOS 8 is now available! CentOS 8 and RedHat En...
1. Introduction Our real servers should not be di...