开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
前言
在文章tagsView实现中,tag删除的方法还未完善
预期效果如下
实现
样式
点击tag,就会在点击处出现选项
先实现基本样式
新建组件ContextMenu.vue,三个li分别绑定三个方法
<template>
<ul class="context-menu-container">
<li @click="onRefreshClick">
{{ $t('msg.tagsView.refresh') }}
</li>
<li @click="onCloseRightClick">
{{ $t('msg.tagsView.closeRight') }}
</li>
<li @click="onCloseOtherClick">
{{ $t('msg.tagsView.closeOther') }}
</li>
</ul>
</template>
<script setup>
// 刷新
const onRefreshClick = () => {}
// 关闭右边tag
const onCloseRightClick = () => {}
// 关闭其他tag
const onCloseOtherClick = () => {}
</script>
<style lang="scss" scoped>
.context-menu-container {
position: fixed;
background: #fff;
z-index: 3000;
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;
}
}
}
</style>
引用contextMenu,在tagView/index.vue中为tag绑定右键点击事件,并声明控制contextMenu是否显示的变量visible,当右键点击,设置visible的值为true
<template>
···
<router-link
...
@contextmenu.prevent="openMenu()"
>
...
</el-scrollbar>
<context-menu
v-show="visible"
></context-menu>
</template>
<script setup>
import ContextMenu from './ContextMenu.vue'
import { ref, reactive, watch } from 'vue'
import { useRoute } from 'vue-router'
...
const visible = ref(false)
/**
* 展示 menu
*/
const openMenu = () => {
visible.value = true
}
</script>
然后需要控制contextMenu出现的位置,需要得到鼠标点击时的x和y值,将其作为动态css引入
<context-menu
v-show="visible"
:style="menuStyle"
></context-menu>
在点击事件中,传入事件event
<router-link
···
@contextmenu.prevent="openMenu($event)"
>
openMenu
const menuStyle = reactive({
left: 0,
top: 0
})
const openMenu = (e) => {
const { x, y } = e
menuStyle.left = x + 'px'
menuStyle.top = y + 'px'
visible.value = true
}
事件处理
删除时需要得到点击tag的index值,所以需要在contextMenu传入index
tagView/index.vue
<router-link
···
@contextmenu.prevent="openMenu($event, index)"
>
{{ tag.title }}
<i
v-show="!isActive(tag)"
class="el-icon-close"
@click.prevent.stop="onCloseClick(index)"
></i>
</router-link>
<context-menu
v-show="visible"
:style="menuStyle"
:index="selectIndex"
></context-menu>
const selectIndex = ref(0)
const openMenu = (e, index) => {
···'
selectIndex.value = index
···
}
在ContextMenu.vue
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
index: {
type: Number,
required: true
}
})
</script>
由于删除需要对tags数据源操作,tags数据源保存在vuex中,所以在mutations中新增删除方法
有三种不同类型的删除,分别删除点击的tag,删除点击右侧tag,和删除其他tag
可以声明一个方法,通过传入不同的类型,确定是哪一种删除操作,执行对应的逻辑,由此传入一个对象,对象中包含删除类型和点击的tag下标值
import { LANG, TAGS_VIEW } from '@/constant'
import { getItem, setItem } from '@/utils/storage'
export default {
namespaced: true,
state: () => ({
sidebarOpened: true,
language: getItem(LANG) || 'zh',
tagsViewList: getItem(TAGS_VIEW) || []
}),
mutations: {
···
removeTagsView(state, payload) {
// 删除点击的tag
if (payload.type === 'index') {
state.tagsViewList.splice(payload.index, 1)
}
// 删除其他tag
else if (payload.type === 'other') {
// 删除之后的
state.tagsViewList.splice(
payload.index + 1,
state.tagsViewList.length - payload.index + 1
)
// 删除之前的
state.tagsViewList.splice(0, payload.index)
}
// 删除右侧tag
else if (payload.type === 'right') {
state.tagsViewList.splice(
payload.index + 1,
state.tagsViewList.length - payload.index + 1
)
}
// 更新本地储存
setItem(TAGS_VIEW, state.tagsViewList)
}
}
}
在ContextMenu.vue触发,刷新直接使用router.go(0)
<script setup>
import { defineProps } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
const props = defineProps({
index: {
type: Number,
required: true
}
})
const store = useStore()
const router = useRouter()
const onRefreshClick = () => {
router.go(0)
}
const onCloseRightClick = () => {
store.commit('app/removeTagsView', {
type: 'right',
index: props.index
})
}
const onCloseOtherClick = () => {
store.commit('app/removeTagsView', {
type: 'other',
index: props.index
})
}
</script>
在tagView/index.vue,删除点击的tag
import { useStore } from 'vuex'
const store = useStore()
// 关闭当前
const onCloseClick = (index) => {
store.commit('app/removeTagsView', {
type: 'index',
index
})
}
关闭处理
接下来处理关闭ContextMenu
可以监听visible的值,visible控制ContextMenu是否显示
当visible为true时,为body绑定鼠标点击事件,触发后将visible的值变为false
当visible为false时,解除事件
tagView/index.vue
import { ref, watch } from 'vue'
const closeMenu = () => {
visible.value = false
}
watch(visible, (val) => {
if (val) {
document.body.addEventListener('click', closeMenu)
} else {
document.body.removeEventListener('click', closeMenu)
}
})
如此便完成contextMenu的所有功能实现