我试图制作一个基于插槽的上下文菜单组件,它应该像这样使用
<template>
<Contextmenu>
<template #contextmenu>
<!--customized contextmenu here-->
<template>
<template #default>
<!--contents here-->
<template>
<Contextmenu>
<template>
右键单击默认插槽时,会出现上下文菜单插槽,单击上下文菜单会发出事件。
组件内部就像这样
<template>
<div class="contextmenu-wrapper" v-if="showContextMenu">
<slot name="contextmenu"></slot>
</div>
<div class="content-wrapper" @contextmenu.prevent.stop="onRightclickContent">
<slot name="default"></slot>
</div>
</template>
div.contextmenu-wrapper
是固定的,onRightclickContent
将设置它的 top
和 left
将其放在正确的位置。在安装的组件上,将注册一个事件侦听器,以在单击上下文菜单外部后关闭上下文菜单。
一切正常,但是当我尝试这个时:
<template>
<div class="wrapper">
<ContextMenu>
<template #contextmenu>
<div class="contextmenu"></div>
</template>
<div class="inner"></div>
<div class="inner"></div>
<div class="inner inner3"></div>
</ContextMenu>
</div>
</template>
<style>
.wrapper {
display: flex;
justify-content: space-evenly;
}
.inner {
width: 250px;
height: 100px;
border: 1px solid #ccc;
background-color: bisque;
}
.inner3 {
flex-grow: 1;
}
.content {
max-width: 100px;
background-color: #3498db;
}
.contextmenu {
width: 100px;
height: 100px;
background-color: azure;
}
</style>
问题是
div.content-wrapper
阻碍了弹性布局。但如果没有它,我如何监听内容上的右键单击事件?
解决方案是这样的:用 div 包裹整个组件,这样类就会落入它,然后将其布局在父组件中:
// ContextMenu.vue
<template>
<div class="wrapper" @contextmenu.prevent.stop="onRightclickContent">
<div class="contextmenu-wrapper" v-if="showContextMenu">
<slot name="contextmenu"></slot>
</div>
<slot name="default"></slot>
</div>
</template>
// parent component
<template>
<div class="wrapper">
<ContextMenu v-for="i in 3" class="inner">
<template #contextmenu>
<div class="contextmenu"></div>
</template>
<div class="content"></div>
</ContextMenu>
</div>
</template>
但是这样就会出现三个相同的右键菜单,内容比较杂乱,给用户带来麻烦。请帮我摆脱困境。
问题解决了。
问题是,我不应该尝试影响父组件中的槽内容。因此,我没有在 slot#content 上绑定事件,同时保持其布局,而是让组件本身成为 Flex 容器:
// ContextMenu.vue
<template>
<div @contextmenu.prevent.stop="onRightclickContent">
<div class="contextmenu-wrapper" v-if="showContextMenu">
<slot name="contextmenu"></slot>
</div>
<slot name="default"></slot>
</div>
</template>
// parent component
<template>
<!--no another wrapper div here!-->
<ContextMenu class="wrapper">
<template #contextmenu>
<div class="contextmenu"></div>
</template>
<!--will be correctly layout now-->
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
</ContextMenu>
</template>
<style>
.wrapper{
display: flex;
}
</style>
class="wrapper"
将落入 ContextMenu 中的根 div,然后它成为 Flex 容器。