vue實(shí)現(xiàn)tab標(biāo)簽(標(biāo)簽超出自動(dòng)滾動(dòng))
當(dāng)創(chuàng)建的tab標(biāo)簽超出頁面可視區(qū)域時(shí)自動(dòng)滾動(dòng)一個(gè)tab標(biāo)簽距離,并可手動(dòng)點(diǎn)擊滾動(dòng)tab標(biāo)簽,實(shí)現(xiàn)效果請(qǐng)看GIF圖
效果預(yù)覽GIF圖

<template>
<div class="main-box">
<button @click="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
// 如有重復(fù)數(shù)據(jù)退出后續(xù)函數(shù)執(zhí)行
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(() => {
// (總共有多少個(gè)tabs - 未偏移時(shí)可見的元素個(gè)數(shù)) * 單個(gè)tab標(biāo)簽元素長度 - 被遮擋tab元素的可見部分的寬度
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))
// 元素實(shí)際寬度 = 元素的寬度 + 外邊距
this.width = marginLeft + marginRight + tabs.children[0].children[0].offsetWidth
/**
* 以下注釋計(jì)算方式用于理解實(shí)現(xiàn)邏輯
**/
// // 可視區(qū)域能放入多少個(gè)元素 = 可視區(qū)域的寬度 / 子元素實(shí)際寬度
// let num = tabs.offsetWidth / this.width
// // 被遮擋tab元素的可見部分的寬度 = 可見區(qū)域的寬度 - (子元素實(shí)際寬度 * num轉(zhuǎn)為整數(shù))
// this.unoccupied = tabs.offsetWidth - (this.width * parseInt(num))
// 最終精簡為取余(得數(shù)跟上面的計(jì)算是一樣的)
this.unoccupied = tabs.offsetWidth % this.width
// 轉(zhuǎn)為整數(shù)
this.tabsCount = parseInt(tabs.offsetWidth / this.width)
})
},
methods: {
add() {
this.count++
this.actionName = `test${this.count}`
},
/**
* 切換tab標(biāo)簽頁
**/
clickTab(name) {
if (this.actionName !== name) {
this.actionName = name
}
},
/**
* 關(guān)閉tab標(biāo)簽頁
**/
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
}
}
}
},
/**
* 往右偏移
**/
next() {
// scrollWidth獲取不準(zhǔn)確
// 使用this.width * this.tabs.length計(jì)算出總長度
let totalWidth = this.width * this.tabs.length
this.$nextTick(() => {
let dom = this.$refs.tabs
// 可視區(qū)域 < 滾動(dòng)區(qū)域(滾動(dòng)區(qū)域大于可視區(qū)域才可以移動(dòng))
// 移動(dòng)距離 + 可視區(qū)域 = 滾動(dòng)區(qū)域的寬度(上一次的寬度,當(dāng)點(diǎn)擊時(shí)才是實(shí)際寬度)< 滾動(dòng)區(qū)域
if (dom.clientWidth < totalWidth && this.moveX + dom.clientWidth < totalWidth) {
// this.moveX為0減去空余空間的寬度
this.moveX += this.moveX ? this.width : this.width - this.unoccupied
this.translateX(this.moveX)
}
})
},
/**
* 往左偏移
**/
previous() {
if (this.moveX > 0) {
this.moveX -= this.width
this.translateX(this.moveX)
}
},
/**
* 開始移動(dòng)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>
到此這篇關(guān)于vue實(shí)現(xiàn)tab標(biāo)簽(標(biāo)簽超出自動(dòng)滾動(dòng))的文章就介紹到這了,更多相關(guān)vue tab標(biāo)簽 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue3封裝自動(dòng)滾動(dòng)列表指令(含網(wǎng)頁縮放滾動(dòng)問題)
- vue如何實(shí)現(xiàn)列表自動(dòng)滾動(dòng)、向上滾動(dòng)的效果(vue-seamless-scroll)
- vue-seamless-scroll 實(shí)現(xiàn)簡單自動(dòng)無縫滾動(dòng)且添加對(duì)應(yīng)點(diǎn)擊事件的簡單整理
- vue實(shí)現(xiàn)動(dòng)態(tài)添加數(shù)據(jù)滾動(dòng)條自動(dòng)滾動(dòng)到底部的示例代碼
- vue中使用vue-router切換頁面時(shí)滾動(dòng)條自動(dòng)滾動(dòng)到頂部的方法
- vue實(shí)現(xiàn)聊天框自動(dòng)滾動(dòng)的示例代碼
相關(guān)文章
vue中接口域名配置為全局變量的實(shí)現(xiàn)方法
今天小編就為大家分享一篇vue中接口域名配置為全局變量的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09
Vue2.0基于vue-cli+webpack Vuex的用法(實(shí)例講解)
下面小編就為大家?guī)硪黄猇ue2.0基于vue-cli+webpack Vuex的用法(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09

