<template>
|
<div class="tags-view-style" style="display: flex; overflow-x: scroll">
|
<i
|
class="el-icon-arrow-left btn"
|
v-if="leftStatus"
|
:class="leftStatus ? 'nor-btn' : 'ban-btn'"
|
@click="scrollToStart()"
|
></i>
|
<div id="tags-box" ref="tags">
|
<div
|
v-for="(item, index) in tags"
|
:key="index"
|
:id="'tags-box-' + index"
|
@contextmenu.prevent="openMenu(item, $event)"
|
:class="isActive(item.url, item.params,index) ? 'active' : ''"
|
class="tagsview"
|
@click="tagsmenu(item, index)"
|
>
|
{{ item.label }}
|
<!-- 这个地方一定要click加个stop阻止,不然会因为事件冒泡一直触发父元素的点击事件,无法跳转另一个路由 -->
|
<span
|
v-if="tags.length > 1"
|
class="el-icon-close tagsicon"
|
@click.stop="handleClose(item, index)"
|
></span>
|
<!-- <ul v-show="visible" class="contextmenu" :style="{left:left+'px',top:top+'px'}">
|
<li @click.stop="rightClose()">关闭</li>
|
<li @click.stop="cleartags($route.path)">关闭其他</li>
|
</ul> -->
|
</div>
|
</div>
|
<i
|
class="el-icon-arrow-right btn"
|
v-if="rightStatus"
|
:class="rightStatus ? 'nor-btn' : 'ban-btn'"
|
@click="scrollToEnd()"
|
></i>
|
</div>
|
</template>
|
|
<script>
|
// 这个就是导入vuex的数据,配合下面...map用
|
import { mapState, mapMutations } from 'vuex'
|
export default {
|
data() {
|
return {
|
// 右键菜单隐藏对应布尔值
|
visible: false,
|
// 右键菜单对应位置
|
top: 0,
|
left: 0,
|
leftStatus: false,
|
rightStatus: false
|
}
|
},
|
computed: {
|
// 引入vuex中state中的tags数据,一样this调用就行
|
...mapState(['tags'])
|
},
|
watch: {
|
// 监听右键菜单的值是否为true,如果是就创建全局监听点击事件,触发closeMenu事件隐藏菜单,如果是false就删除监听
|
visible(value) {
|
if (value) {
|
document.body.addEventListener('click', this.closeMenu)
|
} else {
|
document.body.removeEventListener('click', this.closeMenu)
|
}
|
},
|
$route(to, from) {
|
this.tags.forEach((item, index) => {
|
if (item.url === to.path && item.index === to.query.index) {
|
const tagsDiv = document.getElementById('tags-box')
|
if (index) {
|
tagsDiv.scrollTo(index * 110, 0)
|
} else {
|
tagsDiv.scrollTo(0, 0)
|
}
|
}
|
})
|
}
|
|
},
|
mounted() {
|
this.$refs.tags.addEventListener('scroll', e => {
|
if (this.$refs.tags.scrollLeft > 0) {
|
this.leftStatus = true
|
} else {
|
this.leftStatus = false
|
}
|
if (this.$refs.tags.scrollLeft + this.$refs.tags.clientWidth < this.$refs.tags.scrollWidth) {
|
this.rightStatus = true
|
} else {
|
this.rightStatus = false
|
}
|
}, false)
|
},
|
methods: {
|
// 引入vuex中mutation方法,可以直接this.xxx调用他
|
...mapMutations(['closeTab', 'cleartagsview']),
|
// 点击叉叉删除的事件
|
rightClose() {
|
this.visible = false
|
if (this.tags.length == 1) {
|
return
|
}
|
const index = this.tags.indexOf(this.selectedTag)
|
this.handleClose(this.selectedTag, index)
|
},
|
handleClose(item, index) {
|
if (this.tags.length == 1) {
|
return
|
}
|
// 先把长度保存下来后面用来比较做判断条件
|
const length = this.tags.length - 1
|
// vuex调方法,上面...map引入的vuex方法,不会这种方法的看vue官网文档
|
this.closeTab(item)
|
// 如果关闭的标签不是当前路由的话,就不跳转
|
if (item.url !== this.$route.path) {
|
return
|
}
|
// 判断:如果index和length是一样的,那就代表都是一样的长度,就是最后一位,那就往左跳转一个
|
if (index === length) {
|
// 再判断:如果length=0,也就是说你删完了所有标签
|
if (length === 0) {
|
// 那么再判断:如果当前路由不等于index,也就是我首页的路由
|
if (this.$route.path !== '/index') {
|
// 那么就跳转首页。这一步的意思是:如果删除的最后一个标签不是首页就统一跳转首页,如果你删除的最后一个标签是首页标签,已经在这个首页路由上了,你还跳个什么呢。这不重复操作了吗。
|
this.$router.push({ path: '/index' })
|
}
|
} else {
|
// 那么,如果上面的条件都不成立,没有length=0.也就是说你还有好几个标签,并且你删除的是最后一位标签,那么就往左边挪一位跳转路由
|
this.$router.push({ path: this.tags[index - 1].url,query:{param: this.tags[index - 1].params} })
|
}
|
} else {
|
// 如果你点击不是最后一位标签,点的前面的,那就往右边跳转
|
this.$router.push({ path: this.tags[index].url ,query:{param: this.tags[index].params}})
|
}
|
},
|
// 点击跳转路由
|
tagsmenu(item, index) {
|
console.log('tagsmenu')
|
// 判断:当前路由不等于当前选中项的url,也就代表你点击的不是现在选中的标签,是另一个标签就跳转过去,如果你点击的是现在已经选中的标签就不用跳转了,因为你已经在这个路由了还跳什么呢。
|
if (this.$route.path !== item.url) {
|
// 用path的跳转方法把当前项的url当作地址跳转。
|
this.$router.push({ path: item.url ,query:{param: this.tags[index].params}})
|
const tagsDiv = document.getElementById('tags-box')
|
if (index) {
|
tagsDiv.scrollTo(index * 110, 0)
|
}
|
}
|
this.computeTableHeightView();
|
},
|
computeTableHeightView () { state.tags = []
|
this.$nextTick(() => {
|
let height = window.innerHeight
|
let height6 = (document.getElementsByClassName('common-header') && document.getElementsByClassName('common-header')[0] ? document.getElementsByClassName('common-header')[0].clientHeight:0)
|
// alert(height)
|
let height1 = (document.getElementsByClassName('table-search-form') && document.getElementsByClassName('table-search-form')[0])? document.getElementsByClassName('table-search-form')[document.getElementsByClassName('table-search-form').length-1].clientHeight:0
|
height1 = height1===0? 40:height1+10
|
let height3 = document.getElementsByClassName('main-header') && document.getElementsByClassName('main-header')[0]?document.getElementsByClassName('main-header')[0].clientHeight:0
|
let height4 = document.getElementsByClassName('table-pagination') && document.getElementsByClassName('table-pagination')[0]? document.getElementsByClassName('table-pagination')[0].clientHeight:0
|
let height2 = document.getElementsByClassName('toolbar') && document.getElementsByClassName('toolbar')[0]?document.getElementsByClassName('toolbar')[0].clientHeight:0
|
let height5 = document.getElementsByTagName('thead') && document.getElementsByTagName('thead')[0]? document.getElementsByTagName('thead')[0].clientHeight:0
|
// this.tableHeightNew = height-height4-height3-height2-height1-height5-height6-height7-height8-height9 -height10// 打印高度
|
console.log('view',height,height6,height3 ,height1,height2,height4,height4)
|
console.log('view', height-height4-height3-height2-height1-height5 -height6)
|
})
|
},
|
// 通过判断路由一致返回布尔值添加class,添加高亮效果
|
isActive(route,params, index) {
|
const res =(route === this.$route.path && params== this.$route.query.param)
|
return res
|
},
|
scrollToStart() {
|
const tagsDiv = document.getElementById('tags-box')
|
tagsDiv.scrollTo(0, 0)
|
},
|
scrollToEnd() {
|
const tagsDiv = document.getElementById('tags-box')
|
tagsDiv.scrollTo(tagsDiv.scrollWidth, 0)
|
},
|
// 右键事件,显示右键菜单,并固定好位置。
|
openMenu(tag, e) {
|
this.visible = true
|
this.selectedTag = tag
|
const offsetLeft = this.$el.getBoundingClientRect().left
|
console.log(tag, e)
|
this.left = e.clientX - offsetLeft + 60 // 右键菜单距离左边的距离
|
this.top = e.clientY + 20 // 右键菜单距离上面的距离 这两个可以更改,看看自己的右键菜单在什么位置,自己调
|
},
|
// 隐藏右键菜单
|
closeMenu() {
|
this.visible = false
|
},
|
// 右键菜单关闭所有选项,触发vuex中的方法,把当前路由当参数传过去用于判断
|
cleartags(val) {
|
this.visible = false
|
this.cleartagsview(val)
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.btn {
|
font-size: 20px;
|
line-height: 48px;
|
height: 48px;
|
}
|
.nor-btn {
|
color: #666;
|
cursor: pointer;
|
&:hover {
|
color: #2080f7;
|
}
|
}
|
|
.ban-btn {
|
color: #999;
|
cursor: not-allowed;
|
}
|
|
#tags-box {
|
overflow-x: hidden;
|
white-space: nowrap;
|
flex: 1;
|
// width: 240px;
|
scrollbar-width: none; /* firefox */
|
-ms-overflow-style: none; /* IE 10+ */
|
&::-webkit-scrollbar {
|
display: none; /* Chrome Safari */
|
}
|
}
|
#tags-box::-webkit-scrollbar {
|
display: none; /* Chrome Safari */
|
}
|
//标签导航样式
|
.tagsview {
|
cursor: pointer;
|
// margin-left: 4px;
|
height: 48px;
|
line-height: 48px;
|
padding: 0 8px 0 24px;
|
// border: 1px solid #d8dce5;
|
// border-radius: 5px;
|
color: #000;
|
font-size: 14px;
|
display: inline-block;
|
}
|
//叉号鼠标经过样式
|
.tagsicon:hover {
|
color: #f56c6c;
|
}
|
//标签高亮
|
.active {
|
color: #2080f7;
|
border-bottom: 2px solid #2080f7;
|
}
|
//右键菜单样式
|
.contextmenu {
|
margin: 0;
|
background: #fff;
|
z-index: 100;
|
position: absolute;
|
list-style-type: none;
|
padding: 5px 0;
|
border-radius: 4px;
|
font-size: 12px;
|
font-weight: 400;
|
color: #333;
|
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
|
li {
|
margin: 0;
|
padding: 7px 16px;
|
cursor: pointer;
|
&:hover {
|
background: #eee;
|
}
|
}
|
}
|
.tags-view-style {
|
scrollbar-width: none; /* firefox */
|
-ms-overflow-style: none; /* IE 10+ */
|
&::-webkit-scrollbar {
|
display: none; /* Chrome Safari */
|
}
|
}
|
</style>
|