mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-07 17:07:19 +08:00
feat: add tagViews right click menu
This commit is contained in:
parent
69d2f82835
commit
a0074411ca
@ -1,15 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tags-view" v-if="!showTags">
|
<div ref="containerDom" class="tags-view" v-if="!showTags">
|
||||||
<el-scrollbar :vertical="false" class="scroll-container">
|
<el-scrollbar :vertical="false" class="scroll-container">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in dynamicTagList"
|
v-for="(item, index) in dynamicTagList"
|
||||||
:key="index"
|
:key="index"
|
||||||
:class="['scroll-item', $route.path === item.path ? 'active' : '']"
|
:class="['scroll-item', $route.path === item.path ? 'active' : '']"
|
||||||
|
@contextmenu.prevent.native="openMenu(item, $event)"
|
||||||
>
|
>
|
||||||
<router-link :to="item.path">{{ $t(item.meta.title) }}</router-link>
|
<router-link :to="item.path">{{ $t(item.meta.title) }}</router-link>
|
||||||
<span v-if="index !== 0 " class="el-icon-close" @click="deleteMenu(item)"></span>
|
<span v-if="index !== 0 " class="el-icon-close" @click="deleteMenu(item)"></span>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
<!-- 右键菜单按钮 -->
|
||||||
|
<ul
|
||||||
|
v-show="visible"
|
||||||
|
:style="{ left: buttonLeft + 'px',top: buttonTop + 'px'}"
|
||||||
|
class="contextmenu"
|
||||||
|
>
|
||||||
|
<div v-for="(item,key) in tagsViews" :key="key" style="display:flex; align-items: center;">
|
||||||
|
<li v-if="item.show" @click="selectTag(item,key)">
|
||||||
|
<span>
|
||||||
|
<i :class="item.icon"></i>
|
||||||
|
</span>
|
||||||
|
{{item.text}}
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
<!-- 右侧功能按钮 -->
|
<!-- 右侧功能按钮 -->
|
||||||
<ul class="right-func">
|
<ul class="right-func">
|
||||||
<li>
|
<li>
|
||||||
@ -43,135 +59,211 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang='ts'>
|
||||||
import { useDynamicRoutesHook } from "./tagsHook"
|
import { useDynamicRoutesHook } from "./tagsHook";
|
||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { ref, watchEffect, onBeforeMount, unref, nextTick } from "vue"
|
import { ref, watchEffect, watch, onBeforeMount, unref, nextTick } from "vue";
|
||||||
import { storageLocal } from "/@/utils/storage"
|
import { storageLocal } from "/@/utils/storage";
|
||||||
import { emitter } from "/@/utils/mitt"
|
import { emitter } from "/@/utils/mitt";
|
||||||
import { toggleClass, removeClass } from "/@/utils/operate"
|
import { toggleClass, removeClass } from "/@/utils/operate";
|
||||||
import { homeRoute } from "./type"
|
import { templateRef } from "@vueuse/core";
|
||||||
let refreshDiv = "refresh-div"
|
import { homeRoute } from "./type";
|
||||||
|
let refreshDiv = "refresh-div";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const { deleteDynamicTag, dynamicRouteTags, dRoutes, routesLength } = useDynamicRoutesHook()
|
const {
|
||||||
const route = useRoute()
|
deleteDynamicTag,
|
||||||
const router = useRouter()
|
dynamicRouteTags,
|
||||||
const showTags = ref(storageLocal.getItem("tagsVal") || false)
|
dRoutes,
|
||||||
|
routesLength
|
||||||
|
} = useDynamicRoutesHook();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const showTags = ref(storageLocal.getItem("tagsVal") || false);
|
||||||
|
const containerDom = templateRef<HTMLElement | null>("containerDom", null);
|
||||||
|
|
||||||
const tagsViews = ref([
|
const tagsViews = ref([
|
||||||
{
|
{
|
||||||
icon: "el-icon-refresh-right",
|
icon: "el-icon-refresh-right",
|
||||||
text: "重新加载",
|
text: "重新加载",
|
||||||
divided: false,
|
divided: false,
|
||||||
disabled: false
|
disabled: false,
|
||||||
|
show: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "el-icon-close",
|
icon: "el-icon-close",
|
||||||
text: "关闭当前标签页",
|
text: "关闭当前标签页",
|
||||||
divided: false,
|
divided: false,
|
||||||
disabled: unref(routesLength) > 1 ? false : true
|
disabled: unref(routesLength) > 1 ? false : true,
|
||||||
|
show: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "el-icon-more",
|
icon: "el-icon-more",
|
||||||
text: "关闭其他标签页",
|
text: "关闭其他标签页",
|
||||||
divided: true,
|
divided: true,
|
||||||
disabled: unref(routesLength) > 2 ? false : true
|
disabled: unref(routesLength) > 2 ? false : true,
|
||||||
|
show: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "el-icon-minus",
|
icon: "el-icon-minus",
|
||||||
text: "关闭全部标签页",
|
text: "关闭全部标签页",
|
||||||
divided: false,
|
divided: false,
|
||||||
disabled: unref(routesLength) > 1 ? false : true
|
disabled: unref(routesLength) > 1 ? false : true,
|
||||||
},
|
show: true
|
||||||
])
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
let visible = ref(false);
|
||||||
|
let buttonLeft = ref(0);
|
||||||
|
let buttonTop = ref(0);
|
||||||
|
|
||||||
|
// 当前右键选中的路由信息
|
||||||
|
let currentSelect = ref({});
|
||||||
|
|
||||||
function deleteMenu(item) {
|
function deleteMenu(item) {
|
||||||
let tagslen = storageLocal.getItem("routesInStorage").length
|
let tagslen = storageLocal.getItem("routesInStorage").length;
|
||||||
if (tagslen === 2) {
|
if (tagslen === 2) {
|
||||||
Array.from([1, 2, 3]).forEach(v => {
|
Array.from([1, 2, 3]).forEach(v => {
|
||||||
tagsViews.value[v].disabled = true
|
tagsViews.value[v].disabled = true;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (tagslen === 3) {
|
if (tagslen === 3) {
|
||||||
tagsViews.value[2].disabled = true
|
tagsViews.value[2].disabled = true;
|
||||||
}
|
}
|
||||||
deleteDynamicTag(item, route.path)
|
deleteDynamicTag(item, route.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化页面刷新保证当前路由tabview存在
|
// 初始化页面刷新保证当前路由tabview存在
|
||||||
let stop = watchEffect(() => {
|
let stop = watchEffect(() => {
|
||||||
let parentPath = route.path.slice(0, route.path.lastIndexOf("/"))
|
let parentPath = route.path.slice(0, route.path.lastIndexOf("/"));
|
||||||
dynamicRouteTags(route.path, parentPath)
|
dynamicRouteTags(route.path, parentPath);
|
||||||
})
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 监听只执行一次,但获取不到当前路由,需要下一个事件轮询中取消监听
|
// 监听只执行一次,但获取不到当前路由,需要下一个事件轮询中取消监听
|
||||||
stop()
|
stop();
|
||||||
})
|
});
|
||||||
|
|
||||||
function onFresh() {
|
function onFresh() {
|
||||||
toggleClass(true, refreshDiv, document.querySelector(".rotate"))
|
toggleClass(true, refreshDiv, document.querySelector(".rotate"));
|
||||||
const { path, fullPath } = unref(route)
|
const { path, fullPath } = unref(route);
|
||||||
router.replace({
|
router.replace({
|
||||||
path: "/redirect" + fullPath
|
path: "/redirect" + fullPath
|
||||||
})
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
removeClass(document.querySelector(".rotate"), refreshDiv)
|
removeClass(document.querySelector(".rotate"), refreshDiv);
|
||||||
}, 600)
|
}, 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onClickDrop(key, item) {
|
function onClickDrop(key, item, selectRoute) {
|
||||||
if (item.disabled) return
|
if (item && item.disabled) return;
|
||||||
// 当前路由信息
|
// 当前路由信息
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 0:
|
case 0:
|
||||||
// 重新加载
|
// 重新加载
|
||||||
onFresh()
|
onFresh();
|
||||||
break
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// 关闭当前标签页
|
// 关闭当前标签页
|
||||||
deleteMenu({ path: route.path, meta: route.meta })
|
selectRoute
|
||||||
break
|
? deleteMenu({ path: selectRoute.path, meta: selectRoute.meta })
|
||||||
|
: deleteMenu({ path: route.path, meta: route.meta });
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// 关闭其他标签页
|
// 关闭其他标签页
|
||||||
dRoutes.value = [homeRoute, { path: route.path, meta: route.meta }]
|
dRoutes.value = selectRoute
|
||||||
storageLocal.setItem("routesInStorage", dRoutes.value)
|
? [homeRoute, { path: selectRoute.path, meta: selectRoute.meta }]
|
||||||
tagsViews.value[2].disabled = true
|
: [homeRoute, { path: route.path, meta: route.meta }];
|
||||||
break
|
storageLocal.setItem("routesInStorage", dRoutes.value);
|
||||||
|
tagsViews.value[2].disabled = true;
|
||||||
|
if (selectRoute) router.push(selectRoute.path);
|
||||||
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
// 关闭全部标签页
|
// 关闭全部标签页
|
||||||
dRoutes.value = [homeRoute]
|
dRoutes.value = [homeRoute];
|
||||||
storageLocal.setItem("routesInStorage", dRoutes.value)
|
storageLocal.setItem("routesInStorage", dRoutes.value);
|
||||||
router.push("/welcome")
|
router.push("/welcome");
|
||||||
Array.from([1, 2, 3]).forEach(v => {
|
Array.from([1, 2, 3]).forEach(v => {
|
||||||
tagsViews.value[v].disabled = true
|
tagsViews.value[v].disabled = true;
|
||||||
})
|
});
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
function selectTag(item, key) {
|
||||||
emitter.on("tagViewsChange", (key) => {
|
onClickDrop(key, {}, currentSelect.value);
|
||||||
if (unref(showTags) === key) return
|
}
|
||||||
showTags.value = key
|
|
||||||
})
|
|
||||||
|
|
||||||
emitter.on("changLayoutRoute", (indexPath) => {
|
function openMenu(tag, e) {
|
||||||
let currentLen = storageLocal.getItem("routesInStorage").length
|
if (tag.path === "/welcome") {
|
||||||
|
// 右键菜单为首页,只显示刷新
|
||||||
|
Array.from([1, 2, 3]).forEach(v => {
|
||||||
|
tagsViews.value[v].show = false;
|
||||||
|
});
|
||||||
|
tagsViews.value[0].show = true;
|
||||||
|
} else if (route.path !== tag.path) {
|
||||||
|
// 右键菜单匹配当前路由,显示刷新
|
||||||
|
tagsViews.value[0].show = false;
|
||||||
|
Array.from([1, 2, 3]).forEach(v => {
|
||||||
|
tagsViews.value[v].show = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Array.from([0, 1, 2, 3]).forEach(v => {
|
||||||
|
tagsViews.value[v].show = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSelect.value = tag;
|
||||||
|
const menuMinWidth = 105;
|
||||||
|
const offsetLeft = unref(containerDom).getBoundingClientRect().left;
|
||||||
|
const offsetWidth = unref(containerDom).offsetWidth;
|
||||||
|
const maxLeft = offsetWidth - menuMinWidth;
|
||||||
|
const left = e.clientX - offsetLeft + 15;
|
||||||
|
if (left > maxLeft) {
|
||||||
|
buttonLeft.value = maxLeft;
|
||||||
|
} else {
|
||||||
|
buttonLeft.value = left;
|
||||||
|
}
|
||||||
|
buttonTop.value = e.offsetY * 2;
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMenu() {
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => visible.value,
|
||||||
|
val => {
|
||||||
|
if (val) {
|
||||||
|
document.body.addEventListener("click", closeMenu);
|
||||||
|
} else {
|
||||||
|
document.body.removeEventListener("click", closeMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
emitter.on("tagViewsChange", key => {
|
||||||
|
if (unref(showTags) === key) return;
|
||||||
|
showTags.value = key;
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on("changLayoutRoute", indexPath => {
|
||||||
|
let currentLen = storageLocal.getItem("routesInStorage").length;
|
||||||
if (currentLen === 1) {
|
if (currentLen === 1) {
|
||||||
Array.from([1, 3]).forEach(v => {
|
Array.from([1, 3]).forEach(v => {
|
||||||
tagsViews.value[v].disabled = false
|
tagsViews.value[v].disabled = false;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (currentLen >= 2) {
|
if (currentLen >= 2) {
|
||||||
Array.from([1, 2, 3]).forEach(v => {
|
Array.from([1, 2, 3]).forEach(v => {
|
||||||
tagsViews.value[v].disabled = false
|
tagsViews.value[v].disabled = false;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dynamicTagList: dRoutes,
|
dynamicTagList: dRoutes,
|
||||||
@ -179,9 +271,16 @@ export default {
|
|||||||
showTags,
|
showTags,
|
||||||
onFresh,
|
onFresh,
|
||||||
tagsViews,
|
tagsViews,
|
||||||
onClickDrop
|
onClickDrop,
|
||||||
}
|
visible,
|
||||||
},
|
buttonLeft,
|
||||||
|
buttonTop,
|
||||||
|
openMenu,
|
||||||
|
closeMenu,
|
||||||
|
selectTag,
|
||||||
|
currentSelect
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -220,6 +319,28 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contextmenu {
|
||||||
|
margin: 0;
|
||||||
|
background: #fff;
|
||||||
|
z-index: 3000;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-icon-close {
|
.el-icon-close {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user