feat: 集成多标签右键菜单

This commit is contained in:
张传龙
2022-04-23 19:23:12 +08:00
parent bf63fb5ab7
commit cf1b83d3f1
4 changed files with 212 additions and 23 deletions

View File

@@ -0,0 +1,129 @@
<template>
<n-dropdown
:show="dropdownShow"
:options="options"
:x="x"
:y="y"
placement="bottom-start"
@clickoutside="handleHideDropdown"
@select="handleSelect"
/>
</template>
<script setup>
import { computed } from 'vue'
import { useTagsStore } from '@/store/modules/tags'
import { IconRefresh, IconClose, IconExpand, IconExpandLeft, IconExpandRight } from '@/components/AppIcons'
import { renderIcon } from '@/utils/icon'
import { useAppStore } from '@/store/modules/app'
const props = defineProps({
show: {
type: Boolean,
default: false,
},
currentPath: {
type: String,
default: '',
},
x: {
type: Number,
default: 0,
},
y: {
type: Number,
default: 0,
},
})
const emit = defineEmits(['update:show'])
const tagsStore = useTagsStore()
const appStore = useAppStore()
const options = computed(() => [
{
label: '重新加载',
key: 'reload',
disabled: props.currentPath !== tagsStore.activeTag,
icon: renderIcon(IconRefresh, { size: '14px' }),
},
{
label: '关闭',
key: 'close',
disabled: tagsStore.tags.length <= 1,
icon: renderIcon(IconClose, { size: '14px' }),
},
{
label: '关闭其他',
key: 'close-other',
disabled: tagsStore.tags.length <= 1,
icon: renderIcon(IconExpand, { size: '14px' }),
},
{
label: '关闭左侧',
key: 'close-left',
disabled: tagsStore.tags.length <= 1 || props.currentPath === tagsStore.tags[0].path,
icon: renderIcon(IconExpandLeft, { size: '14px' }),
},
{
label: '关闭右侧',
key: 'close-right',
disabled: tagsStore.tags.length <= 1 || props.currentPath === tagsStore.tags[tagsStore.tags.length - 1].path,
icon: renderIcon(IconExpandRight, { size: '14px' }),
},
])
const dropdownShow = computed({
get() {
return props.show
},
set(show) {
emit('update:show', show)
},
})
const actionMap = new Map([
[
'reload',
() => {
appStore.reloadPage()
},
],
[
'close',
() => {
tagsStore.removeTag(props.currentPath)
},
],
[
'close-other',
() => {
tagsStore.removeOther(props.currentPath)
},
],
[
'close-left',
() => {
tagsStore.removeLeft(props.currentPath)
},
],
[
'close-right',
() => {
tagsStore.removeRight(props.currentPath)
},
],
])
function handleHideDropdown() {
dropdownShow.value = false
}
function handleSelect(key) {
const actionFn = actionMap.get(key)
actionFn && actionFn()
handleHideDropdown()
}
</script>
<style lang="scss" scoped></style>

View File

@@ -2,56 +2,77 @@
<div class="tags-wrapper" :style="{ height: useTheme.tags.height + 'px' }">
<n-space>
<n-tag
v-for="tag in useTags.tags"
v-for="tag in tagsStore.tags"
:key="tag.path"
:type="useTags.activeTag === tag.path ? 'primary' : 'default'"
:closable="useTags.tags.length > 1"
:type="tagsStore.activeTag === tag.path ? 'primary' : 'default'"
:closable="tagsStore.tags.length > 1"
@click="handleTagClick(tag.path)"
@close.stop="handleClose(tag.path)"
@close.stop="tagsStore.removeTag(tag.path)"
@contextmenu.prevent="handleContextMenu($event, tag)"
>
{{ tag.title }}
</n-tag>
</n-space>
</div>
<ContextMenu
v-model:show="contextMenuOption.show"
:current-path="contextMenuOption.currentPath"
:x="contextMenuOption.x"
:y="contextMenuOption.y"
/>
</template>
<script setup name="Tags">
import { watch } from 'vue'
import ContextMenu from './ContextMenu.vue'
import { nextTick, reactive, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useTagsStore } from '@/store/modules/tags'
import { useThemeStore } from '@/store/modules/theme'
const route = useRoute()
const router = useRouter()
const useTags = useTagsStore()
const tagsStore = useTagsStore()
const useTheme = useThemeStore()
const contextMenuOption = reactive({
show: false,
x: 0,
y: 0,
currentPath: '',
})
watch(
() => route.path,
() => {
const { name, path } = route
const title = route.meta?.title
useTags.addTag({ name, path, title })
useTags.setActiveTag(path)
tagsStore.addTag({ name, path, title })
},
{ immediate: true }
)
const handleTagClick = (path) => {
useTags.setActiveTag(path)
tagsStore.setActiveTag(path)
router.push(path)
}
const handleClose = (path) => {
if (path === useTags.activeTag) {
const activeIndex = useTags.tags.findIndex((item) => item.path === path)
if (activeIndex > 0) {
router.push(useTags.tags[activeIndex - 1].path)
} else {
router.push(useTags.tags[activeIndex + 1].path)
}
}
useTags.removeTag(path)
function showContextMenu() {
contextMenuOption.show = true
}
function hideContextMenu() {
contextMenuOption.show = false
}
function setContextMenu(x, y, currentPath) {
Object.assign(contextMenuOption, { x, y, currentPath })
}
// 右击菜单
async function handleContextMenu(e, tagItem) {
const { clientX, clientY } = e
hideContextMenu()
setContextMenu(clientX, clientY, tagItem.path)
await nextTick()
showContextMenu()
}
</script>