修改BUG点:
1 修改文字样式,使鼠标点击文字旁边的空白区域均可以点击上
2 修改当前页右击后,选择关闭其它,执行后,仅剩一个页时,没有颜色问题
先看图
功能:
重新写了tag标签页
新增鼠标右键菜单
右键菜单新增功能:关闭其它,关闭左侧,关闭右侧
剩一个标签时,则无法删除,且右键菜单无法点击,代码有判断(没截图,自己领会即可)
======================================================
猥琐发育,别浪(直接代码一波)
<template>
<div class="menu-tags">
<template v-if="data.length != 0">
<div class="tag-item" v-for="(item, index) in data" :key="item.name + index" @contextmenu.prevent="rightClick($event, item)">
<!-- <span v-if="data.length==1" class="active" @click="handleSelect(item)">{{ item.meta.title }}</span> -->
<span :class="['item-title',item.isActive||data.length==1 ? 'active' : '']" @click="handleSelect(item)">{{ item.meta.title }}</span>
<span class="item-btn iconfont icon-guanbi2" @click="handleClose(item)"></span>
</div>
</template>
<div class="right-menu" ref="rightMenu" v-show="rightMenu">
<!-- <div class="menu-item" @click="handleRefresh($event)">刷新</div> -->
<div :class="['menu-item', data.length == 1 ? 'menu-item_disabled' : '']" @click="handleRightMenuClose($event, 'other')">
<span class="menu-item_licon iconfont icon-guanbiqita"></span>关闭其它
</div>
<div :class="['menu-item', data.length == 1 ? 'menu-item_disabled' : '']" @click="handleRightMenuClose($event, 'left')">
<span class="menu-item_licon iconfont icon-guanbizuoce"></span>关闭左侧
</div>
<div :class="['menu-item', data.length == 1 ? 'menu-item_disabled' : '']" :disabled="data.length == 1 ? true : false" @click="handleRightMenuClose($event, 'right')">
<span class="menu-item_licon iconfont icon-guanbiyouce"></span>关闭右侧
</div>
</div>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
name: 'LlMenuTags',
props: {},
data() {
return {
data: [],
rightMenu: false,
activeMenuItem: {},
btnDisabled: false,
}
},
computed: {
...mapState({
tagData() {
return this.$store.state.tagsRouter
},
}),
...mapGetters({
getTagsRouterData: 'getTagsRouter', // 获取标签路由信息
}),
},
// 定义引入的组件
components: {},
//变量监听
watch: {},
// 页面初始化
created() {},
// 页面DOM加载完成
mounted() {
let _this = this
_this.init()
},
//离开页面时执行
destroyed() {},
watch: {},
// 页面方法
methods: {
...mapMutations({
mySetRouterTagActive: 'setRouterTagActive', // clickTotal 是mutation 里的方法,totalAlise是重新定义的一个别名方法,本组件直接调用这个方法
}),
init() {
let _this = this
_this.$set(_this, 'data', [])
_this.$nextTick(() => {
_this.$set(_this, 'data', _this.$store.state.tagsRouter)
})
},
handleRightMenuClose(event, direction) {
let _this = this
//只有一项时,不能关闭
if (_this.data.length == 1) {
return
}
//关闭左侧
_this.$store.commit('delRoutes', {
direction: direction, //方向
item: _this.activeMenuItem,
})
_this.$nextTick(() => {
_this.handleGoto(_this.activeMenuItem.path)
})
},
rightClick(event, item) {
let _this = this
event = event || window.event
//屏蔽样式
event.preventDefault
? event.preventDefault()
: (event.returnValue = false)
//获取坐标
var x = event.clientX //视口的位置
var y = event.clientY
_this.$set(_this, 'activeMenuItem', item)
_this.$nextTick(() => {
_this.rightMenu = true
let myRightMouseMenu = _this.$refs.rightMenu
//页面高度
let bodyHeight = document.body.offsetHeight
//显示菜单位置
myRightMouseMenu.style.top = y + 'px'
myRightMouseMenu.style.left = x + 'px'
// 监听-点击菜单之外区域时,隐藏
document.body.addEventListener('click', _this.hideMenu)
})
},
hideMenu(event) {
let _this = this
event = event || window.event
event.stopPropagation()
event.preventDefault()
_this.rightMenu = false
// 清除监听-点击菜单之外区域时,隐藏
document.body.removeEventListener('click', _this.hideMenu)
},
handleClose(item) {
let _this = this
if (_this.data.length == 1) {
return false
}
//
item.isActive = true
let tempData = [..._this.data]
_this.$store.commit('delRoute', {
item,
isSameRoute: _this.$route.path == item.path,
})
if (tempData.length != 0 && _this.$route.path == item.path) {
//跳转
let gotoPath = ''
for (let i = 0; i < tempData.length; i++) {
if (tempData[i].path == item.path) {
if (tempData[i + 1] != undefined) {
gotoPath = tempData[i + 1].path
} else if (tempData.length != 0) {
gotoPath = tempData[0].path
}
break
}
}
if (gotoPath != '') {
_this.handleGoto(gotoPath)
}
}
},
handleSelect(item) {
let _this = this
//如果是当前页,则不跳
if (item.name != _this.$route.name) {
_this.$router.push({
path: item.path,
})
_this.mySetRouterTagActive(item)
_this.$nextTick(() => {
_this.init()
})
}
},
handleGoto(path) {
let _this = this
if (_this.$common.isNull(path)) {
return false
}
_this.$router.push({
path: path,
})
},
},
}
</script>
<style lang="less" scoped>
.right-menu {
position: absolute;
background: #fff;
border: 1px solid #ccc;
border-radius: 4px;
.menu-item {
font-size: 14px;
padding: 0 20px;
height: 40px;
line-height: 40px;
cursor: pointer;
.menu-item_licon {
width: 16px;
}
}
.menu-item:hover {
background: #c3c3c3;
}
.menu-item_disabled {
cursor: not-allowed;
}
}
.menu-tags {
margin: 10px 16px 0 16px;
.tag-item {
padding: 0 25px 0 0;
margin-right: 10px;
margin-bottom: 10px;
display: inline-block;
background: #fafafa;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
cursor: pointer;
transition: 0.3s;
position: relative;
.item-title {
width: 100%;
display: inline-block;
padding: 8px 16px;
}
.tag-title::selection {
background: none;
}
.item-btn {
font-size: 12px;
position: absolute;
top: 8px;
right: 0;
width: 16px;
height: 16px;
line-height: 16px;
}
.active {
color: #63d5ce;
}
}
.tag-item:hover {
color: #63d5ce;
}
}
</style>
vuex
import Vue from 'vue'
import router from '@/router'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: {},
tagsRouter: [],
},
getters: {
getUser(state) {
//获取本地用户信息
let user = localStorage.getItem('user')
if (user != null) {
state.user = JSON.parse(user)
return JSON.parse(user)
} else {
router.push({ path: '/login' })
return state.user
}
},
getTagsRouter(state) {
//获取标签路由信息
debugger
return state.tagsRouter
},
},
mutations: {
setUser(state, user) {
//设置
state.user = { ...user }
//存储本地
localStorage.setItem('user', JSON.stringify({ ...user }))
},
setRouterTagActive(state, routeItem) {
//设置当前的tag页为活动页
for (let i = 0; i < state.tagsRouter.length; i++) {
let item = state.tagsRouter[i]
state.tagsRouter[i].isActive = false
if (state.tagsRouter[i].name === routeItem.name) {
state.tagsRouter[i].isActive = true
}
}
},
addRoute(state, routeItem) {
//选择菜单后,添加至本地路由信息中
let flog = false
for (let i = 0; i < state.tagsRouter.length; i++) {
let item = state.tagsRouter[i]
if (state.tagsRouter[i].name === routeItem.name) {
flog = true
break
}
}
if (!flog) {
state.tagsRouter.push({
path: routeItem.path,
name: routeItem.name,
meta: routeItem.meta,
})
}
},
delRoute(state, params) {
//删除tags路由项
if (state.tagsRouter.length != 0) {
let itemIndex = 0
for (let i = 0; i < state.tagsRouter.length; i++) {
let item = state.tagsRouter[i]
if (state.tagsRouter[i].meta.menuKey === params.item.meta.menuKey) {
//
itemIndex = i
state.tagsRouter.splice(i, 1)
break
}
}
//跳除后的跳转
}
},
delRoutes(state, params) {
//删除多项tags路由项
if (state.tagsRouter.length != 0) {
let flogIndex = 0
let sum = 0
let tempArr = state.tagsRouter
if (params.direction == 'left') {
//从左侧开始删除
for (let i = 0; i < state.tagsRouter.length; i++) {
let item = state.tagsRouter[i]
if (state.tagsRouter[i].meta.menuKey === params.item.meta.menuKey) {
// 记录当前位置
flogIndex = i
break
}
sum++
}
state.tagsRouter.splice(0, sum)
} else if (params.direction == 'right') {
//删除右侧所有路由
for (let i = 0; i < state.tagsRouter.length; i++) {
let item = state.tagsRouter[i]
if (state.tagsRouter[i].meta.menuKey === params.item.meta.menuKey) {
//
sum = state.tagsRouter.length - i + 1
flogIndex = i
break
}
}
state.tagsRouter.splice(flogIndex, sum)
} else {
// 关闭其它
state.tagsRouter.splice(0, state.tagsRouter.length)
state.tagsRouter.push({
path: params.item.path,
name: params.item.name,
meta: params.item.meta,
})
}
//跳除后的跳转
}
},
},
actions: {
doSomething(context, val) {
//应用:this.$store.dispatch("doSomething",{})
//提交mutations内的方法:context.commit("setUser",val)
},
},
modules: {},
})
route.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '@/store/index'
Vue.use(VueRouter)
// 页面进度条
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
NProgress.configure({
easing: 'ease', // 动画方式
speed: 500, // 递增进度条的速度
showSpinner: false, // 是否显示加载ico
trickleSpeed: 200, // 自动递增间隔
minimum: 0.3, // 初始化时的最小百分比
})
const routes = [
{
path: '/',
name: 'index',
meta: { title: '首页', icon: 'home', menuKey: '1', menu: true },
redirect: '/Dashboard/DashboardIndex',
component: () =>
import(/* webpackChunkName: "about" */ '../views/HomeView.vue'),
},
{
path: '/Dashboard',
name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'bar-chart', menuKey: '2' },
component: () => import('../views/HomeView.vue'),
children: [
{
path: 'DashboardIndex',
name: 'DashboardIndex',
meta: { title: 'DashboardIndex', icon: '', menuKey: '2.1' },
component: () => import('@/views/dashboard/Dashboard.vue'),
},
],
},
{
path: '/block',
name: 'block',
meta: { title: '区块链基础网络', icon: 'apartment', menuKey: '3' },
component: () => import('../views/HomeView.vue'),
children: [
{
path: 'BlockChainSetting',
name: 'BlockChainSetting',
meta: { title: '区块链配置', icon: '', menuKey: '3.1' },
component: () => import('@/views/blockchain/BlockChainSetting.vue'),
},
{
path: 'BlockChainSetUp',
name: 'BlockChainSetUp',
meta: { title: '区块链搭建', icon: '', menuKey: '3.2' },
component: () => import('@/views/blockchain/BlockChainSetUp.vue'),
},
{
path: 'BlockChainNetInfo',
name: 'BlockChainNetInfo',
meta: { title: '网络状态', icon: '', menuKey: '3.3' },
component: () => import('@/views/blockchain/BlockChainNetInfo.vue'),
},
],
},
{
path: '/NewOrganization',
name: 'NewOrganization',
meta: { title: '新增组织', icon: 'apartment', menuKey: '4' },
component: () => import('../views/HomeView.vue'),
children: [
{
path: 'JoinChannel',
name: 'JoinChannel',
meta: { title: '加入通道', icon: 'apartment', menuKey: '4.1' },
component: () => import('@/views/neworganization/JoinChannel.vue'),
},
{
path: 'NewNode',
name: 'NewNode',
meta: { title: '新增节点', icon: 'apartment', menuKey: '4.2' },
component: () => import('@/views/neworganization/NewNode.vue'),
},
{
path: 'CreateChannel',
name: 'CreateChannel',
meta: { title: '创建新通道', icon: 'apartment', menuKey: '4.3' },
component: () => import('@/views/neworganization/CreateChannel.vue'),
},
],
},
{
path: '/About',
name: 'About',
meta: { title: 'About', icon: '' },
component: () => import('../views/AboutView.vue'),
},
{
path: '/login',
name: 'login',
meta: { title: '登录', icon: '' },
component: () => import('../views/login/Login.vue'),
},
]
const router = new VueRouter({
mode: 'hash',
base: process.env.BASE_URL,
routes,
})
router.beforeEach((to, from, next) => {
// 每次切换页面时,调用进度条
NProgress.start()
if (to.meta.menuKey != undefined) {
store.commit('addRoute', to)
store.commit('setRouterTagActive', to)
}
next()
})
//当路由进入后:关闭进度条
router.afterEach(() => {
// 在即将进入新的页面组件前,关闭掉进度条
NProgress.done()
})
const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(to) {
return VueRouterPush.call(this, to).catch((err) => err)
}
export default router
最后引入组件即可
提示,路由信息,跟据自己的情况走,可做简单的参考就行了。