主要思路,每点击一下侧边栏菜单(也就是访问URL),根据这个URL匹配的路由中meta属性中的自定义的isTabView属性,判断是否需要显示为TAB,是的话就增加这个TAB标签或者切换到这个TAB标签。
本TAB组件主要特点:
1.菜单联动,切换标签时菜单也会切换(其实是因为router.path)
2.标签数据都保存到sessionStorage,页面打开时也会根据sessionStorage恢复之前的标签
3.添加功能左移动,右移动(当标签书过多时),关闭当前,关闭所有
还有个是标签:首页(/control)是一直保留的,可以自行修改
第一步肯定是拦截到这个访问URL的事件,每次访问都要调用addOpendPage方法
router.afterEach((to, from, next) => {
let param = {app: router.app, name: to.name, params: to.params, query: to.query, meta: to.meta, path: to.path}
store.dispatch('addOpendPage', param)
NProgress.done() // 结束Progress
})
然后直接放核心代码,也是使用vuex的,在store目录下的modules目录,保存为tabview.js
import * as utils from '@/utils'
import router from "../../router"
const tabview = {
state: {
pageOpendList: []
},
mutations: {
/**
* 初始化设置tab 一般默认首页,页面加载时调用
* @method tabOpendListInit
*/
setOpenedList(state) {
const local = sessionStorage.pageOpendList && JSON.parse(sessionStorage.pageOpendList).length > 0
if (local) {
state.pageOpendList = JSON.parse(sessionStorage.pageOpendList)
}
// var exist = false;
// for (var k in state.pageOpendList) {
// if (state.pageOpendList[k].path == '/control')
// exist = true;
// }
//默认添加首页
if (!utils.objArrayContains(state.pageOpendList,'path','/control')) {
state.pageOpendList.splice(0, 0, {
meta: {title: "首页", isTabView: true},
name: "control",
params: {},
path: "/control",
query: {}
})
sessionStorage.pageOpendList = JSON.stringify(state.pageOpendList)
}
},
/*
* @描述: 关闭所有标签
* @参数注释:
* @param state
* @返回值:
* @创建人: LoneKing
* @创建时间: 16:04 2019/7/26
*/
closeAllOpenedList(state) {
sessionStorage.pageOpendList = ''
state.pageOpendList = []
router.push({
name: "control"
})
},
/**
* 每次打开页面都会经过此方法,用于合并参数
* @method setPageOpendList
*/
setPageOpendList(state, res) {
const {index, query, params, meta, path} = res
let opendPage = state.pageOpendList[index]
if (params) {
opendPage.params = params
}
if (query) {
opendPage.query = query
}
if (meta) {
opendPage.meta = meta
}
if (path) {
opendPage.path = path
}
state.pageOpendList.splice(index, 1, opendPage)
sessionStorage.pageOpendList = JSON.stringify(state.pageOpendList)
},
increateTag(state, tag) {
const local = sessionStorage.pageOpendList && JSON.parse(sessionStorage.pageOpendList).length > 0
if (local) {
state.pageOpendList = JSON.parse(sessionStorage.pageOpendList)
}
if (!utils.objArrayContains(state.pageOpendList,'path',tag.path)) {
state.pageOpendList.push(tag)
sessionStorage.pageOpendList = JSON.stringify(state.pageOpendList)
}
},
/**
* @param {*} state
* @param {当前页签信息} obj
* @param { 当前实例 } obj.vm
* @param { 路由name} obj.name
*/
closeOpendList(state, name) {
const lists = state.pageOpendList
for (let i = 0; i < lists.length; i++) {
if (lists[i].name === name) {
const lastName = state.pageOpendList[i - 1].name
state.pageOpendList.splice(i, 1)
sessionStorage.setItem('pageOpendList', JSON.stringify(state.pageOpendList))
router.push({
name: lastName
})
}
}
},
/**
* @param {*} state
* @param {当前页签信息} obj
* @param { 当前实例 } obj.vm
* @param { 路由name} obj.name
*/
closeOtherOpendList(state, name) {
const lists = state.pageOpendList
for (let i = 0; i < lists.length; i++) {
if (lists[i].name === name) {
state.pageOpendList = []
state.pageOpendList.push(lists[i])
//默认添加首页
if (!utils.objArrayContains(state.pageOpendList,'path','/control')) {
state.pageOpendList.splice(0, 0, {
meta: {title: "首页", isTabView: true},
name: "control",
params: {},
path: "/control",
query: {}
})
sessionStorage.pageOpendList = JSON.stringify(state.pageOpendList)
}
break
}
}
}
},
actions: {
/**
* @method addOpendPage
* @param vm 当前实例
* @param name 当前路由name
* @param query 查询参数
* @param param 查询参数
* 一般放在router BeforeAfter(BeforeEach) 执行
*/
addOpendPage: ({commit, state}, param) => {
let {vm, name, params = '', query = '', meta = '', path = ''} = param
let pageOpendList = state.pageOpendList
let opendLen = pageOpendList.length
let i = 0
let tagHasOpened = false
if (opendLen > 0) {
for (; i < opendLen; i++) {
//本来用的是name 但是viewList会出现重复情况 于是改成path
if (pageOpendList[i].path === path) {
commit('setPageOpendList', {
index: i,
params,
query,
meta,
path,
})
tagHasOpened = true
break
}
}
}
/**
* 注入参数 如果tab未打开
*/
if (!tagHasOpened && name) {
let tag = {
name: name
}
if (params) {
tag.params = params
}
if (query) {
tag.query = query
}
if (meta && meta.isTabView) {
tag.meta = meta
} else if (meta && !meta.isTabView) {
return
}
if (path) {
tag.path = path
}
commit('increateTag', tag)
}
}
}
}
export default tabview
getter.js只需要这一个属性就行
const getters = {
pageOpendList: state => state.tabview.pageOpendList
}
export default getters
TabView组件代码,保存为TabView.js 然后直接import,调用就行
<template>
<div class="tag-view-wrap">
<el-button @click="moveLeft" class="left left-button" icon="el-icon-d-arrow-left" circle
style="padding:0;" type="default"></el-button>
<div class="tabs-wrap" id="tabs-wrap">
<div :style="{marginLeft:tabMarginLeft+'px'}" class="tabs breadcrumb-move">
<el-tag
:class="{ active: item.path === $route.path }"
:closable="item.name !== 'control'"
:key="item.id"
@click.native="jump(item)"
@close="close(item)"
class="tag-view"
v-for="item in pageOpendList">
{{menuTitle[item.path]}}
</el-tag>
</div>
</div>
<el-dropdown class="right close-button" trigger="click">
<el-button size="mini" type="default">
操作<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="closeOther">关闭其他</el-dropdown-item>
<el-dropdown-item @click.native="closeAll">关闭所有</el-dropdown-item>
<el-dropdown-item @click.native="clearMenuCache">清除菜单缓存</el-dropdown-item>
<el-dropdown-item @click.native="clearTabCache">清除Tab缓存</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button @click="moveRight" circle class="right right-button" icon="el-icon-d-arrow-right"
type="default"></el-button>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
data() {
return {
tabMarginLeft: 0
}
},
computed: {
...mapGetters([
'pageOpendList',
'menuTitle',
]),
},
watch: {
//自动调整tab位置滚动
pageOpendList: {
handler: function (newVal, oldVal) {
let tabs = document.getElementsByClassName("tag-view")
let wrapWidth = document.getElementById("tabs-wrap").offsetWidth
let currentActiveTabWidth = 0
for (let index = 0; index < newVal.length; index++) {
//+4是因为每个tab之间margin-left 4
currentActiveTabWidth += tabs[index].offsetWidth + 4
if (this.$route.path === newVal[index].path) {
log(this.$route.path)
break
}
}
if (currentActiveTabWidth > wrapWidth) {
this.moveRight()
} else {
this.moveLeft()
}
},
deep: true
}
},
beforeCreate() {
this.$store.commit('setOpenedList')
},
methods: {
clearMenuCache() {
sessionStorage.menus = ''
window.location.reload()
},
clearTabCache() {
sessionStorage.pageOpendList = ''
window.location.reload()
},
moveLeft() {
this.tabMarginLeft = 0
},
moveRight() {
let totalWidth = this.getTabsWidth()
let wrapWidth = document.getElementById("tabs-wrap").offsetWidth
if (totalWidth > wrapWidth) {
this.tabMarginLeft = wrapWidth - totalWidth - 180
}
},
getTabsWidth() {
let totalWidth = 0
let tabs = document.getElementsByClassName("tag-view")
for (let i = 0; i < tabs.length; i++) {
//+4是因为每个tab之间margin-left 4
totalWidth += tabs[i].offsetWidth + 4
}
return totalWidth
},
closeOther() {
this.$store.commit("closeOtherOpendList", this.$route.name)
},
closeAll() {
this.$store.commit("closeAllOpenedList")
},
jump(item) {
const {params, query} = item
/**
* @description
* 下面四种情况考虑到参数传递的问题,所以单独处理
*/
if (params) {
this.$router.push({
name: item.name,
params: params
})
return
}
if (query) {
this.$router.push({
name: item.name,
query: query
})
return
}
if (query && params) {
this.$router.push({
name: item.name,
params: params,
query: query
})
return
}
this.$router.push({
name: item.name
})
},
close(item) {
this.$store.commit("closeOpendList", item)
}
}
}
</script>
<style lang="scss">
.tag-view-wrap {
border-bottom: 1px solid rgb(230, 230, 230);
width: 90%;
display: inline-block;
white-space: nowrap;
overflow: hidden;
.tabs-wrap {
width: 88%;
float: left;
overflow: hidden;
}
.left-button {
position: relative;
top: 12px;
width: 28px;
height: 28px;
padding: 0px !important;
}
.right-button {
position: relative;
top: 12px;
width: 28px;
height: 28px;
padding: 0px !important;
}
.close-button {
padding-left: 3px;
}
.tabs {
width: 100%;
white-space: nowrap;
.tag-view {
cursor: pointer;
margin: 0 4px;
&.active {
background-color: #e63979;
color: #fff;
.el-tag__close {
color: #fff;
}
}
}
}
}
</style>
相关代码打包
[reply2down]http://down.lkcloud.top/BlogFile/tabview.zip[/reply2down]
你没设置缓存?每次点击都重新加载,还没完全
想试一试
我来试试
试一下,看能不能行
试试
试一下
好东西,试一试
优秀
好东西
感谢
好东西,试一试,感谢分享
楼主写的真不错,有很大的帮助
谢谢分享
谢谢
谢谢分享,万分感谢
先试一下啊
谢谢分享
先试一试
谢谢分享了。
谢谢分享
先试一试,感谢
谢谢分享
感谢分享
试下,感谢
谢谢博主分享了